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

require('colors')
url = require('url')
path = require('path')
config = require('./config')
GitProxy = require('./git-proxy')
Activity = require('./models/activity')
{spawn} = require('child_process')
BufferStream = require('bufferstream')
{debug_log} = require('./helper')


class HttpBackend
    constructor: () ->
        @proxy = new GitProxy()

    respond: (req, res, project) =>
        query_string = url.format({ query: req.query })
        { owner: owner_id,
        id: project_id,
        repo: repo_name,
        service } = req.params
        path_info = req.params.join("") # '*' in '/:owner/:id.git*'
        if path_info.length > 1 and path_info[-1..] is "/"
            path_info = path_info[...-1]
        service = req.query.service
        repo_name = req.params.repo

        # authorisation check
        user_id = "stranger"
        pushing = service is "git-receive-pack"
        is_owner = false
        if req.isAuthenticated()
            user_id = req.session.auth.user.name
            is_owner = user_id is owner_id
        # TODO authorisation
        return res.send("", 401) if pushing and not is_owner

        # CGI stuff
        content_type = req.header('content-type',
            "application/x-#{service}-request")
        env =
            GIT_HTTP_EXPORT_ALL: yes
            GIT_PROJECT_ROOT: path.join(project.hash, repo_name)
            REMOTE_USER: owner_id
            REMOTE_ADDR: "foo@mail"
            CONTENT_TYPE: content_type
            REQUEST_METHOD: req.method
            REQUEST_URI: "#{path_info}#{query_string}"
            QUERY_STRING: query_string[1..] # some '/' snipped
            PATH_INFO: path_info
        accept = req.header('accept-encoding')
        env['HTTP_CONTENT_ENCODING'] = accept if accept # FIXME crude :O

        # spawn
        child = spawn 'git', ['http-backend', '--stateless-rpc'],
            cwd: path.join(config.cwd, config.repositories)
            env: env

        buffer = new BufferStream(encoding:'binary', size:'flexible')

        # pipe child output to res but intercept with BufferStream
        child.stdout.pipe(buffer)
        buffer.pipe(res)

        # input for child is this POST body
        if req.method is "POST"
            req.body.pipe(child.stdin)
            req.body.stream.disable()

        # git http backend error printing
        child.stderr.on 'data', (err) ->
            # TODO debug_log
            console.log('git http-backend:'.red, err.toString('utf8'))

        # sane exit of the child if necessary
        process.once 'exit', child.kill
        child.on 'exit', () ->
            process.removeListener('exit', child.kill)
            delete child

        # HTTP header parser
        buffer.split "\r\n", (line, token) =>
            line = line.toString()
            i = line.indexOf(":")
            if i != -1
                res.header(line[...i], line[i+2..])
            if line.length is 0
                if path_info is "/git-receive-pack"
                    @on_push(buffer, user_id, project, repo_name) # TODO put in whole user object
                else
                    @on_pull(buffer, user_id, project, repo_name)
                buffer.disable(token)
                unless buffer.splitters.length
                    buffer.setSize('none')
                else
                    buffer.flush() unless buffer.paused

    on_push: (buffer, user, project, repo) =>
        #(new Activity('push', user, project)).save()
        buffer.on 'end', () ->
            # clear the cache group, any function would work
            project[repo].gitcache.commits.clear_group()

    on_pull: (buffer, user, project, repo) =>
        # @proxy.response(buffer, user) FIXME


# exports

module.exports = HttpBackend

