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

Project = require '../models/project'
User = require '../models/user'
{ Highlight } = require('highlight')
Path = require 'path'
async = require 'async'
# XXX validate data
# XXX differentiate on repo
# XXX get_uri is config stuff
# XXX get_uri and its resources should contain the 5src instance, right?

uris_website =
    commit:
        (owner, project, sha) -> "/#{owner}/#{project}/.commit/#{sha}"
    user:
        (user_id) -> "/#{user_id}"

uri_layout =
    website: uris_website

get_uri = (view_type, resource_type, args...) ->
    uri_layout[view_type][resource_type](args...)

class SioBase

    constructor: () ->
        @get_uri = get_uri

class Sio extends SioBase

    # newly defined methods are automatically as public socket io events
    # use SioBase for methods which are not events

    diffs: (socket, { owner, project, sha }, cb) =>
        cb ?= (d) -> socket.emit 'diff', d
        Project.fetch owner, project, (err, user, project, objects) =>
            return cb {} if err
            sha = "#{sha}^..#{sha}" if -1 is sha.indexOf ".."
            project.source.gitcache.diffs sha, (diffs) =>
                for diff in diffs
                    cb diff
                return

    blob: (socket, { owner, project, path, sha }, cb) =>
        index = 0
        path ?= "README"
        cb ?= (b) -> socket.emit 'blob', b
        Project.fetch owner, project, (err, user, project, objects) =>
            rev = {}
            rev[sha] = path
            rv = project.source.gitcache.cat rev, (data) =>
                for line in Highlight(data.toString()).split('\n')
                    index++
                    do (line, index) ->
                        setTimeout (-> cb {line, index}), Math.random()*342 # hihi
                return

    commits: (socket, { owner, project, n, skip }, cb) =>
        n ?= 20
        skip ?= 0
        cb ?= (c) -> socket.emit 'commit', c
        Project.fetch owner, project, (err, user, project, objects) =>
            commits = project.source.gitcache.commits {skip, n}
            commits.on 'data', (commit) =>
                commit.index = skip++
                cb commit

    user: (socket, author, cb) =>
        cb ?= (u) -> socket.emit 'user', u
        User.lookup_author author, (err, user, object) =>
            return cb {notfound:yes,name:author.name,email:author.email} if err
            if user
                user = user.compact()
                user.uri = '/'+user.id
                user.email = author.email
            else
                user =
                    notfound: yes
                    email: author.email
                    name: author.name
            cb user

    project: (socket, { owner, project }, cb) =>
        cb ?= (p) -> socket.emit 'project', p
        Project.fetch owner, project, (err, user, project, objects) =>
            cb project.compact()

    type_filetype_map: {
        'blob': 'file'
        'tree': 'folder'
    }

    trees: (socket, { owner, project, path, recursive }, cb) =>
        trees_args = []
        if recursive
            trees_args.push '-r'
        path ?= '.'
        if path != '.' and path[-1..] != '/'
            path += '/'
        trees_args.push 'HEAD', path

        cb ?= (t) -> socket.emit 'tree', t
        Project.fetch owner, project, (err, user, project, objects) =>
            repo = project.source
            repo.load_empty =>
                trees = repo.gitcache.trees trees_args...
                trees.on 'data', (tree) =>
                    tree.filetype = "#{@type_filetype_map[tree.type]}"
                    tree.basename = Path.basename(tree.path)
                    tree.dirname  = Path.dirname (tree.path)
                    cb tree

module.exports = Sio

