#!/usr/bin/env perl

# Use mandatory external modules
use strict;
use Cwd;
use File::Basename;
use Data::Dumper;
use POSIX;
use Config;
use DBI;

# Determine installation dir name
our $SELF_DIR = dirname(dirname(dirname(Cwd::abs_path(__FILE__))));

# Include parts of the system
require $SELF_DIR . '/lib/config.pm';
require $SELF_DIR . '/lib/log.pm';
require $SELF_DIR . '/lib/roles.pm';

# Read config file
our $config = ReadConfig("mmm_agent.conf");

if (scalar(@ARGV) < 1) {
    print "ERROR: Usage: $0 <master_host>\n\n";
    exit(101);
}

my $master_host = shift(@ARGV);
if (!defined($config->{host}->{$master_host})) {
    print "ERROR: Invalid master host ($master_host)\n"
}

print StartSlave($master_host);

exit(0);

#-----------------------------------------------------------------
sub StartSlave($) {
    my $master_host = shift;

    my $this = $config->{this};
    my $peer = $master_host;
    
    # get self connection info
    my $host = $config->{host}->{$this}->{ip};
    my $port = $config->{host}->{$this}->{port};
    my $user = $config->{host}->{$this}->{user};
    my $pass = $config->{host}->{$this}->{password};

    # connect to servers (this)
    my $this_dbh = MysqlConnect($host, $port, $user, $pass);
    return "ERROR: Can't connect to MySQL (host = $host:$port, user = $user)!"  if (!$this_dbh);

    # Get slave info
    my $slave_status = MysqlQuery($this_dbh, "SHOW SLAVE STATUS");
    return "ERROR: SQL Query Error: " . $this_dbh->errstr unless($slave_status);
    
    my $wait_log = $slave_status->{Master_Log_File};
    my $wait_pos = $slave_status->{Read_Master_Log_Pos};
    my $old_peer_ip = $slave_status->{Master_Host};
    
    if ($old_peer_ip) {
        my $old_peer = FindHostByIP($old_peer_ip);
        if (!$old_peer) {
            return "ERROR: Invalid master host in slave status!";
        }

        # get peer connection info
        my $old_peer_host = $config->{host}->{$old_peer}->{ip};
        my $old_peer_port = $config->{host}->{$old_peer}->{port};
        my $old_peer_user = $config->{host}->{$old_peer}->{user};
        my $old_peer_pass = $config->{host}->{$old_peer}->{password};

        my $old_peer_dbh = MysqlConnect($old_peer_host, $old_peer_port, $old_peer_user, $old_peer_pass);
        if ($old_peer_dbh) {
            my $row = MysqlQuery($old_peer_dbh, "SHOW MASTER STATUS");
            return "ERROR: SQL Query Error: " . $old_peer_dbh->errstr unless($row);
            
            $wait_log = $row->{File};
            $wait_pos = $row->{Position};
            $old_peer_dbh->disconnect;
        }
    }
    
    # Sync with old master logs or slave logs
    my $res = ExecuteQuery($this_dbh, "SELECT MASTER_POS_WAIT('$wait_log', $wait_pos)");
    return "ERROR: SQL Query Error: " . $this_dbh->errstr unless($res);
    
    # Stop slave
    $res = ExecuteQuery($this_dbh, "STOP SLAVE");
    return "ERROR: SQL Query Error: " . $this_dbh->errstr unless($res);

    # get peer connection info
    my $peer_host = $config->{host}->{$peer}->{ip};
    my $peer_port = $config->{host}->{$peer}->{port};
    my $peer_user = $config->{host}->{$peer}->{user};
    my $peer_pass = $config->{host}->{$peer}->{password};

    my $peer_dbh = MysqlConnect($peer_host, $peer_port, $peer_user, $peer_pass);
    if (!$peer_dbh) {
        return "ERROR: Can't connect to master host (host = $peer_host:$peer_port, user = $peer_user)!";
    }
    
    # Get master position
    my $row = MysqlQuery($peer_dbh, "SHOW MASTER STATUS");
    return "ERROR: SQL Query Error: " . $this_dbh->errstr unless($row);
    
    my $master_log = $row->{File};
    my $master_pos = $row->{Position};

    $peer_dbh->disconnect;

    my $repl_user = $peer_user;
    my $repl_pass = $peer_pass;

    if (defined($config->{replication_user}) && defined($config->{replication_password})) {
        $repl_user = $config->{replication_user};
        $repl_pass = $config->{replication_password};
    }

    # Change master
    my $sql = "CHANGE MASTER TO " .
              "  MASTER_HOST='$peer_host'," .
              "  MASTER_PORT=$peer_port," .
              "  MASTER_USER='$repl_user'," .
              "  MASTER_PASSWORD='$repl_pass'," .
              "  MASTER_LOG_FILE='$master_log'," .
              "  MASTER_LOG_POS=$master_pos";
    my $res = ExecuteQuery($this_dbh, $sql);
    return "ERROR: SQL Query Error: " . $this_dbh->errstr unless($res);
    
    # Start slave
    $res = ExecuteQuery($this_dbh, "START SLAVE");
    return "ERROR: SQL Query Error: " . $this_dbh->errstr unless($res);

    return "OK";
}

#-----------------------------------------------------------------
sub MysqlConnect($$$$) {
    my ($host, $port, $user, $pass) = @_;
    
    my $dsn = "DBI:mysql:host=$host;port=$port";
    return DBI->connect($dsn, $user, $pass, { PrintError => 0 });
}

#-----------------------------------------------------------------
sub MysqlQuery($$) {
    my ($dbh, $query) = @_;

    LogDebug("MYSQL QUERY: $query");

    my $sth = $dbh->prepare($query);
    my $res = $sth->execute;
    return undef unless($res);

    my $row = $sth->fetchrow_hashref;
    $sth->finish;

    return $row;
}

#-----------------------------------------------------------------
sub ExecuteQuery($$) {
    my ($dbh, $query) = @_;

    LogDebug("MYSQL EXEC: $query");

    my $sth = $dbh->prepare($query);
    return $sth->execute;
}

#-----------------------------------------------------------------
sub FindHostByIP($) {
    my $ip = shift;
    
    my $hosts = $config->{host};
    foreach my $host (keys(%$hosts)) {
        return $host if ($hosts->{$host}->{ip} eq $ip);
    }
    
    return 0;
}


