### 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/>
###

path = require('path')
gt = require('gettext')
async = require('async')
slug = require('slug')
config = require('../config')
appconfig = require('../appconfig')
sha1 = require('../helper').hash('sha1')
Repository = require('./repository')
Model = require('./skeleton')
User = require('./user')
db = require('../db')

class Project extends Model
    __spaceholder__: null # coffeescript bug or feature?
    whitelist: ["_id", "_rev", "type", "date", "id", "name",
                "description", "hash", "owner"]
    defaults:
        id: Math.random()
        type: "project"
        date: new Date()
        name: "unamed"
        description: ""
    mapping:
        owner: (x) ->
            _id: x._id
            id: x.id

    constructor: (data) ->
        super(data)
        @_id = "project/#{@owner.id}/#{@id}"
        @hash or= sha1.hash(@owner.id + @id + Math.random())
        @path = path.join(config.cwd, config.repositories, @hash)
        https = config.https and "s" or ""
        @clone_url =
            http: "http#{https}://#{config.url}/#{@owner.id}/#{@id}.git"
            git:  "git://#{config.url}/#{@owner.id}/#{@id}.git"
        # this will put f.e. source in this
        for repo in appconfig.repositories
            this[repo] = new Repository
                path: path.join(@path, repo)
                branch: "master"
                clone_url:
                    http: "http#{https}://#{config.url}/#{@owner.id}/#{@id}.#{repo}.git"
                    git:  "git://#{config.url}/#{@owner.id}/#{@id}.#{repo}.git"
        @__defineGetter__ 'repositories', () =>
            load: => load_repository.apply(this, arguments)
        @__defineGetter__ 'descline', () =>
            descline = @description
            if descline
                descline = descline[..descline.indexOf("\n")]
            else
                descline = gt._("no description")
            descline = descline[0 ... 79] + "…" if descline.length > 80
            descline
        yes # we are done

    set_branch: (branches) =>
        for repo in appconfig.repositories
            this[repo].branch = branches[repo] if branches[repo]?


load_repository = (branches, callback) ->
    # sets .repo, .heads AND .empty
    load = (branch, callback) =>
        unless branch in appconfig.repositories
            throw Error("branch '#{branch}' not found.")
        repo = this[branch]
        branch = branches[branch]
        repo.branch = branch if typeof branch is 'string'
        merge = ->
            repo.merge_trees_and_commits(repo.trees, repo.commits)
            callback(null)
        x = todo: 2
        repo.load_empty =>
            repo.load_trees => merge() unless --x.todo
            repo.load_commits => merge() unless --x.todo
    async.forEach Object.keys(branches), load, (err) =>
        @body = 'empty' if @source.empty
        callback(err)


Project.fetch = (userid, id, callback) ->
    _id = "project/#{slug(userid)}/#{slug(id)}"
    User.fetch userid, (err, user, objects) =>
        return callback(err, user, null, objects) if err
        project = objects.all[_id]
        err = gt._("project not found") unless project
        callback(err, user, project, objects)


Project.fetch_and_load = (userid, id, branches, callback) ->
    Project.fetch userid, id, (err, user, project, objects) ->
        return callback(err, user, project, objects) if err
        project.repositories.load branches, (err) ->
            callback(err, user, project, objects)

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

# exports

module.exports = Project

