### codetube
    Copyright (C) 2011 payload payload@lavabit.com
    Copyright (C) 2011 dodo dodo.the.last@gmail.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>
###

gt = require('gettext')
slug = require('slug')
gravatar = require('gravatar')
Model = require('./skeleton')
config = require('../config')
db = require('../db')
async = require('async')
sha256 = require('../helper').hash('sha256')
{ isObject } = require('underscore')
{ debug_log, parse_author } = require('../helper')

eyes = require('eyes')

class User extends Model
    __spaceholder__: null # coffeescript bug or feature?
    blacklist: ['activities']
    defaults:
        type: "user"
        date: new Date()
        name: "unnamed"
        id: Math.random()
        projects: []
        emails: {}
        passphrase: Math.random()
    mapping:
        projects: (x) -> {_id: y._id} for y in x

    constructor: (args...) ->
        super
        @_id = 'user/'+@id
        @activities = []

    isAuthenticated: (req) =>
        req.isAuthenticated() and @id is req.session.auth.user.name

    avatar: (opts) =>
        opts ?= {}
        opts = {size:opts} unless typeof opts is 'object'
        avatar = "/.static/img/megusta.png"
        return opts['default'] or opts.d or avatar unless @email?
        _ = "http://" + config.url
        gravatar.url @email, {
            d:_+(opts['default'] or opts.d or avatar)
            r:   opts.rating     or opts.r or 'g'
            s:   opts.size       or opts.s or 48
            },   opts.https

    add_email: (email) =>
        return if @emails[email]
        @emails[email] =
            confirmed: no
            created:   new Date
            hash:      sha256.hash(email.toLowerCase())


User.fetch = (id, cb) ->
    id = slug(id)
    _id = "user/#{id}"
    query = startkey: [_id, {}], endkey: [_id], descending: yes
    db.view "user/data", query, (err, got) =>
        if err
            return cb(err, null, Model.compile(null))
        objects = Model.compile(got)
        user = objects.all[_id] or null
        unless user
            err = { code: 'user not found', who: id }
        cb(err, user, objects)

User.list = (limit, skip, cb) ->
    db.view "user/all", { limit, skip }, (err, got) =>
        if err
            cb(err, got)
        else
            users = (new User(doc.value) for own doc in got)
            users.total = got.total_rows
            cb(err, users)
###
# User.lookup_author

Searches for the best match on a local user instance. This
includes all email addresses the user has registered as well
as the user name. See dbschema user/comit_user_lookup

author: string containing identifiable information or object with name and email

###
User.lookup_author = (author, final_callback) ->
    if isObject(author)
        user_info = {name:author.name}
        # filter values
        user_info.email = parse_author(author.email).email
    else
        user_info = parse_author(author)

    # causes all alter arriving requests to simply end when match was found
    finished = false

    # this needs to be done in parallel as couchdb does not like multi key
    # requests on reduce views. include_docs does not work eigther
    # actual lookup wrapper. looks up the requested value in the lookup view
    wrap_results = (value) ->
        if not value
            return undefined
        return (callback) ->
            query = startkey:value, endkey:value, group:true
            db.view "user/commit_user_lookup", query, (err, got) ->
                if err
                    return callback(null, null)
                if got and got.length and not finished
                    # mark that we h
                    finished = true
                    _id = got[0].value._id.substr(5)
                    # fetch the actual user
                    User.fetch _id, (err, user, objs) =>
                        if user == null
                            return
                        final_callback(err, user)

                callback(null,null)

    # run the search in parallel. first result that matches
    # will call the final_callback. if not fired the final
    # function call will execute final_callback
    async.parallel
        email: wrap_results(user_info.email)
        name: wrap_results(user_info.name)
        , (err, res) ->
            if not finished
                final_callback(null, null)



# exports

module.exports = User

