require 'build-tool/vcs/base'
require 'build-tool/errors'

module BuildTool; module VCS

    class GitError < BuildTool::Error; end

    class GitConfiguration < BaseConfiguration

        def name
            "git"
        end

        attr_accessor :remote

        def initialize( mod = nil )
            super( mod )
            @remote = {}
        end

        def vcs( mod )
            @module = mod
            Git.new( self )
        end

        def track_remote
            rc = self.module.remote_path.split('/')
            # If there is only one string we assume it is the branch name from
            # origin
            return "origin" if rc.length == 1
            return rc[0]
        end

        def track_branch
            rc = self.module.remote_path.split('/')
            # If there is only one string we assume it is the branch name from
            # origin
            return rc[0] if rc.length == 1
            return rc[1..-1].join( '/' )
        end


    end

    #
    # Implementation for the git version control system.
    #
    class Git < Base

        def initialize( config )
            super( config )
            @remote = {}
            @vcs = nil
        end

        #
        ### ATTRIBUTES
        #
        def name
            "git"
        end

        def fetching_supported?
            true
        end

        #
        ### METHODS
        #

        def checkedout?
            return false if !local_path_exist?
            if !Pathname.new( local_path ).join( ".git" ).exist?
                raise Base::VcsError, "Checkout path #{local_path} is not a git repo!"
            end
            return true
        end

        # Initialize the local repository
        def clone
            # Check if path exists
            if local_path_exist?
                raise GitError, "Failed to create repository at '#{local_path}': Path exists"
            end

            # Create the directory
            FileUtils.mkdir_p( local_path ) if !$noop

            # Initialize the repository
            if git( "init", local_path ) != 0
                raise GitError, "Error while initializing the repo `git init #{local_path}'`: #{$?}"
            end

            config.remote.each do |name, val|
                if git( "remote add #{name} #{val.url}" ) != 0
                    raise GitError, "Error while initializing the repo `git remote add #{name} #{val.url}`: #{$?}"
                end
            end

            cmd = "remote add origin #{repository.url}"
            if git( cmd, local_path ) != 0
                raise GitError, "Error while initializing the repo `#{cmd}`: #{$?}"
            end

            logger.info <<-EOS
The following command sometimes fails when issued from this script. Reason unknown. The
best chance you have is issuing the command manually!
#{local_path}: #{cmd}
#{local_path}: git checkout -b #{config.track_branch} #{config.track_remote}/#{config.track_branch}
            EOS

            fetch()

            cmd = "checkout -b #{config.track_branch} #{config.track_remote}/#{config.track_branch}"
            if git( cmd, local_path ) != 0
                raise GitError, "Error while initializing the repo `#{cmd}`: #{$?}"
            end

        end

        def remote?( name )
            found = false
            git( "remote" ) do |line|
                found = true if line == name
            end
            return found
        end

        # Fetch from +repository+
        #
        # Initializes the local clone if it does not exist.
        def fetch()
            if !checkedout? and !$noop
                clone
            end
            cmd = "fetch #{config.track_remote}"
            if ( rc = git( cmd ) ) != 0
                raise GitError, "Error while fetching: #{rc}"
            end
        end

        def git( command, wd = local_path, &block )
            rc = self.class.execute "git #{command}", wd, &block
            if rc != 0
                raise GitError, "git #{command || "" } failed with error code #{rc}";
            end
            rc
        end

        def rebase
            if 0 != ( git "rebase #{config.track_remote}/#{config.track_branch}" )
                raise GitSvnError, "Error while rebasing the repo with `git rebase git-svn: #{$?}"
            end
        end

    end # class Git

    class GitRemote

        attr_accessor :server
        attr_accessor :path
        attr_reader   :name

        def initialize( name )
            @name = name
            @path = nil
        end

        def url
            url = ""
            if @server
                url = @server.url
            end
            if @path
                url = "#{url}/#{path}"
            end
            url
        end

        def to_s
            "REMOTE: #{name} #{url}"
        end

    end # class Remote

end; end # module BuildTool::VCS