package Common::Deploy::SwitchBranch;

use lib '/app/tools/common/lib';
use Common::RSApp;
use Common::Deploy;

use Data::Dumper;

use Common::Config;

use base 'Common::Script';

sub _common_options {
    {
        list => {
            short       => 'l',
            description => 'List all branches on this system',
        },
        which => {
            short       => 'w',
            description => 'Which branch am I currently using',
        },
        branch => {
            short       => 'b',
            description => 'Specify branch to switch to',
            parameter   => 's'
        },
        verbose => {
            short       => 'v',
            description => 'Display verbose output'
        },
        debug => {
            short       => 'd',
            description => 'Display debug output'
        },
        help => {
            short       => 'h',
            description => 'display this screen'
        },

    };
}

sub start {
    my $class = shift;
    my $self = ref($class) ? $class : $class->new(@_);

    $self->_parse_options();

    my $app = new Common::RSApp( clientID => 0 );

    $self->debug( "Repository Dir: " . $self->_repository() );
    $self->debug( "Mysql Repository Dir: " . $self->_mysqlRepository() );
    $self->debug( "Mysql Dir: " . $self->_mysqlDir() );
    $self->debug( "Code Dir: " . $self->_codeDir() );

    Common::Deploy->validateDirectoryStructure();

    if ( $self->param('help') ) {
        $self->usage();
    } elsif ( $self->param('list') ) {
        $self->_listBranches();
    } elsif ( $self->param('which') ) {
        $self->_currentBranch();
    } else {
        $self->switchBranch( $self->param('branch') );
    }
}

sub _repository {
    my $self = shift;
    return exists( $self->{"_$option"} ) ? $self->{"_$option"} : Common::Deploy->repository();
}

sub _mysqlRepository {
    my $self = shift;
    return exists( $self->{"_$option"} ) ? $self->{"_$option"} : Common::Deploy->mysqlRepository();
}

sub _mysqlDir {
    my $self = shift;
    return exists( $self->{"_$option"} ) ? $self->{"_$option"} : Common::Deploy->mysqlDir();
}

sub _codeDir {
    my $self = shift;
    return exists( $self->{"_$option"} ) ? $self->{"_$option"} : Common::Deploy->codeDir();
}

sub _apacheInit {
    my $self   = shift;
    my $config = new Common::Config();
    return $config->get("apache_init") || return;
}

sub _mysqlInit {
    my $self   = shift;
    my $config = new Common::Config();
    return $config->get("mysql_init") || return;
}

sub _listBranches {
    my $self          = shift;
    my $repository    = $self->_repository();
    my $currentBranch = Common::Deploy->getCurrentBranch() || "";
    my @branches      = Common::Deploy->getLocalBranches();

    foreach my $branch ( sort @branches ) {
        printf( "%s\t%s\n", $branch, $branch eq $currentBranch ? "(current)" : "" );
    }
}

sub _getNextBranch {
    my $self          = shift;
    my $repository    = $self->_repository();
    my $currentBranch = Common::Deploy->getCurrentBranch() || "";
    my @branches      = Common::Deploy->getLocalBranches();
    die "No local branches checked out" unless (@branches);

    my $found;
    my $newBranch;

    foreach my $branch ( sort @branches ) {
        if ($found) {
            $newBranch = $branch;
            $found     = undef;
        }

        if ( $branch eq $currentBranch ) {
            $found = 1;
        }
    }

    $newBranch = $branches[0] unless ($newBranch);

    return $newBranch;
}

sub _currentBranch {
    my $self                  = shift;
    my $currentBranch         = Common::Deploy->getCurrentBranch() || "";
    my $currentDatabaseBranch = Common::Deploy->getCurrentDatabaseBranch() || "";

    print "$currentBranch (db: $currentDatabaseBranch)\n";
}

sub switchBranch {
    my $self    = shift;
    my $branch  = shift;
    my $current = Common::Deploy->getCurrentBranch() || "";
    my $nextBranch;

    if ($branch) {
        $nextBranch = $branch;
    } else {
        $nextBranch = $self->_getNextBranch() || 'trunk';
    }

    print "Switching from branch '$current' to '$nextBranch'\n";
    $self->_switchCode($nextBranch);
    $self->_switchDatabase($nextBranch);
    $self->_restartApache();
}

sub _switchCode {
    my $self       = shift;
    my $branch     = shift || die;
    my $repository = $self->_repository();
    my $codeDir    = $self->_codeDir();

    die "Branch does not exist in repository: '$branch'"                       unless ( -e "$repository/$branch" );
    die "Directory doesn't appear to be a valid branch: '$repository/$branch'" unless ( -d "$repository/$branch/code" );

    if ( -e $codeDir || -l $codeDir ) {
        unlink($codeDir) || die "Failed to unlink code symlink '$codeDir': $!";
    }

    symlink( "$repository/$branch/code", $codeDir )
      || die "Failed to create symlink '$repository/$branch': $!";

}

sub _switchDatabase {
    my $self                  = shift;
    my $branch                = shift || die;
    my $repository            = $self->_mysqlRepository();
    my $mysqlDir              = $self->_mysqlDir();
    my $currentDatabaseBranch = Common::Deploy->getCurrentDatabaseBranch();

    $self->debug("  -- Attempting to switch the database to '$branch'");

    my $newBranch = $branch;

    unless ( -e "$repository/$newBranch" ) {
        $self->debug("'$repository/$branch' does not exists, falling back to trunk database");
        $newBranch = 'trunk';

        die "$repository/$newBranch does not exists" unless ( -e "$repository/$newBranch" );
    }

    print " ++ Using database $newBranch\n";

    die "$repository/$newBranch is not a directory" unless ( -d "$repository/$newBranch" );

    if ( $newBranch eq $currentDatabaseBranch ) {
        $self->debug("MySQL branch hasn't changed, not restarting");
    } else {
        if ( -e $mysqlDir || -l $mysqlDir ) {
            unlink($mysqlDir) || die "Failed to unlink code symlink '$mysqlDir': $!";
        }

        die "Failed to remove '$mysqlDir'" if ( -e "$mysqlDir" );

        symlink( "$repository/$newBranch", $mysqlDir )
          || die "Failed to create symlink '$mysqlDir': $!";

        $self->_restartMySQL();
    }
}

sub _restartApache {
    my $self       = shift;
    my $apacheInit = $self->_apacheInit();

    die "'$apacheInit' is not executable" unless ( -x $apacheInit );

    print " -- restarting Apache\n";

    my $cmd = "sudo $apacheInit restart 2>&1";
    Common::Log::Debug("EXECUTE: $cmd");

    my $output = `$cmd`;

    Common::Log::Debug($output);

    if ($?) {
        die "Failed to executed command: $cmd\n\n$output";
    }
}

sub _restartMySQL {
    my $self      = shift;
    my $mysqlInit = $self->_mysqlInit();

    die "'$mysqlInit' is not executable" unless ( -x $mysqlInit );

    print " -- restarting MySQL\n";

    my $cmd = "sudo $mysqlInit restart 2>&1";
    Common::Log::Debug("EXECUTE: $cmd");

    my $output = `$cmd`;

    Common::Log::Debug($output);

    if ($?) {
        die "Failed to executed command: $cmd\n\n$output";
    }
}

1;
