# -*- coding: UTF-8 -*-

require 'build-tool/vcs/base'

require 'mj/mixins/inherited_attributes'

module BuildTool; module VCS

    class SvnConfiguration < BaseConfiguration

        include MJ::Mixins::InheritedAttributes

        def initialize
            super
            @only = nil
            @repository = nil
            @remote_path = nil
        end

        def name
            "svn"
        end

        def vcs( mod )
            raise StandardError if @module and ! mod.equal?( @module )
            @module = mod
            Svn.new( self )
        end

        inherited_attr_accessor :only

        def copy_configuration( other )
            super
            @only = nil     # Do not copy nil
        end

        attr_writer :repository
        def repository
            return @repository if @repository             # Our repository
            return parent.repository if @parent       # Our parents repository
            raise ConfigurationError, "No repository configured for module #{self.module ? self.module.name : 'unknown' }."
        end

        attr_writer :remote_path
        def remote_path
            return @remote_path if @remote_path
            return parent.remote_path if @parent
            return @module.name
        end

    end

    #
    # Implementation for the subversion version control system.
    #
    class Svn < Base

        class SvnError < BuildTool::Error; end

        # def initialize( *args )
        #     super( *args )
        # end

        class << self

            svn_available = nil

            # Is the git executable available?
            def svn_available?
                return @svn_available unless @svn_available.nil?
                %x( svn --version 2>&1 )
                @svn_available = $?.success?
                return @svn_available
            end

        end


        #
        ### ATTRIBUTES
        #
        def name
            "svn"
        end

        def fetching_supported?
            false
        end


        #
        ### METHODS
        #

        def checkedout?
            return false if !local_path_exist?
            if !File.exists? "#{local_path}/.svn"
                logger.debug("Checkout path #{local_path} is not a svn repo")
                return false
            end
            return true
        end

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

            # Create the directories parent dir.
            FileUtils.mkdir_p( File.dirname( local_path ) ) if !$noop

            # Init the repository
            if config.only
                svn "checkout --depth=files #{repository.url}/#{remote_path} #{local_path}", local_path.dirname
                config.only.each do |elem|
                    svn "update --depth=infinity #{elem}", local_path
                end
            else
                svn "checkout --depth=infinity #{repository.url}/#{remote_path} #{local_path}", local_path.dirname
            end
            return true
        end

        def ready_for_fetch
            if not Svn.svn_available?
                logger.info( "#{config.module.name}: Calling `svn` failed!" )
                return false
            end
            return true
        end

        def fetch( verbose = false )

            if !checkedout?
               return clone
            end

            if verbose
                svn "log -r HEAD:BASE -q" do |line|
                    logger.info( line )
                end
            end

            svn "update"

            return true
        end

        # Returns the last changed revision on the remote repository.
        # Return 0 if the last changed revision could not be determined.
        def last_changed_rev
            info = Hash.new
            svn( "info #{repository.url}/#{remote_path}", nil ) {
                |line|
                key, value = line.chomp.split( ':', 2 )
                info[key] = value
            }
            return 777777 if $noop
            version = info["Last Changed Rev"];
            raise SvnError, "Failed to determine revision for #{repository.url}/#{remote_path}" if version.nil?
            return version
        end

        def prepare_for_fetch
            # If our server has an associated ssh-key, add it to the ssh-agent.
            return check_for_sshkey( config.repository.sshkey )
        end

        def remote_path
            @config.remote_path
        end

        def repository
            config.repository
        end


        # Call svn with command
        def svn( command, wd = local_path, &block )
            self.class.svn( command, wd, &block )
        end

        def self.svn( command, wd, &block )
            rc = self.execute( "svn " + command, wd, &block )
            if rc != 0
                raise SvnError, "Command 'svn #{command}' failed with error code #{rc}!"
            end
            rc
        end

        def rebase( verbose = false )
            # Rebasing is not supported
            0
        end

        def[]( var )
            case var

            when nil

            else
                # *TODO* raise correct exception
                raise NotImplementedError, "#{var}"
            end
        end

        def[]=( var, val )
            case var

            when nil

            else
                # *TODO* raise correct exception
                raise NotImplementedError, "#{var}"
            end
        end
    end # class Svn


end; end # module BuildTool::VCS