using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using MySQL.Grt;
using MySQL.Utilities;
using MySQL.GUI.Workbench.Plugins;

namespace MySQL.GUI.Workbench.Plugins.Wb
{
  using System.Collections;
  using Pages = LinkedList<PageInfo>;

  public partial class WBPluginUpdaterPages : WizardPluginPages
  {
    private Wb_updater pluginBE;
    private bool downloadSucceeded;
    private bool downloadCancelled;

    public WBPluginUpdaterPages(WizardPlugin wizard)
      : base(wizard)
    {
      InitializeComponent();

      pluginBE = new Wb_updater(wizard.GrtManager);

/* // now connection settings are taken from wb_options
      AddPage(connSettingsPanel,
        InitializeConnSettingsPage,
        CleanupConnSettingsPage,
        ProcessConnSettingsPage,
        null,
        null,
        "Connection settings",
        "Provide information needed to access Internet.");
*/
      AddPage(verCheckPanel,
        InitializeVerCheckPage,
        CleanupVerCheckPage,
        ProcessVerCheckPage,
        null,
        null,
        "Check for new version",
        "Get information on latest available versions via Internet.");

      AddPage(authPanel,
        InitializeAuthPage,
        CleanupAuthPage,
        ProcessAuthPage,
        null,
        IsAuthPageToBeSkipped,
        "Authentication",
        "Provide credentials to access download server.");

      AddPage(downloadPanel,
        InitializeDownloadPage,
        CleanupDownloadPage,
        ProcessDownloadPage,
        null,
        null,
        "Download/Install",
        "Download chosen release and install it.");
    }

#region ConnSettings
    private string InitializeConnSettingsPage()
    {
      if (-1 == proxyTypeCombo.SelectedIndex && 0 < proxyTypeCombo.Items.Count)
        proxyTypeCombo.SelectedIndex = 0;
      return "";
    }

    private string CleanupConnSettingsPage()
    {
      return "";
    }

    private string ProcessConnSettingsPage()
    {
      pluginBE.proxy_type(proxyTypeCombo.Text);

      // proxy_server= [server]:[port]
      {
        String proxyServer = proxyServerTB.Text;
        if (0 < proxyServer.Length && 0 < proxyPortTB.Text.Length)
          proxyServer += ":" + proxyPortTB.Text;
        pluginBE.proxy_server(proxyServer);
      }

      // proxy_userpwd= [user]:[password]
      {
        String proxyUserPwd = proxyLoginTB.Text;
        if (0 < proxyUserPwd.Length && 0 < proxyPasswTB.Text.Length)
          proxyUserPwd += ":" + proxyPasswTB.Text;
        pluginBE.proxy_userpwd(proxyUserPwd);
      }

      return "";
    }
#endregion ConnSettings


#region AuthPage
    private string InitializeAuthPage()
    {
      return "";
    }

    private string CleanupAuthPage()
    {
      return "";
    }

    private string ProcessAuthPage()
    {
      // server_userpwd= [user]:[password]
      {
        String serverUserPwd = srvLoginTB.Text;
        if (0 < serverUserPwd.Length && 0 < srvPasswTB.Text.Length)
          serverUserPwd += ":" + srvPasswTB.Text;
        pluginBE.server_userpwd(serverUserPwd);
      }

      return "";
    }

    private string IsAuthPageToBeSkipped()
    {
      String res = "1";
      if (0 != pluginBE.rel_authorization(releaseCombo.SelectedIndex))
        res = "";
      return res;
    }
#endregion AuthPage


#region VerCheck
    void ResetCombo(ComboBox combo, List<String> items)
    {
      combo.Items.Clear();
      foreach (String item in items)
        combo.Items.Add(item);
      if (0 < combo.Items.Count)
        combo.SelectedIndex = 0;
    }

    private string InitializeVerCheckPage()
    {
      List<String> messages = new List<String>();
      string errMsg = "";

      fetchRelInfoLabel.TaskState = MySQLTaskStatusLabelState.TaskOpen;
      checkVerLabel.TaskState = MySQLTaskStatusLabelState.TaskOpen;
      StepProlog(verCheckResultLabel, verCheckStageLabel);

      // initialization task

      // reset controls to neutral state
      {
        releaseCombo.Items.Clear();
        mirrorCombo.Items.Clear();

        curVerLabel.Text = "";
      }

      // set current version info
      curVerLabel.Text = pluginBE.current_version_details();

      // notes
      messages.Add("Note: additional log files will be stored in \"" + pluginBE.working_dir() + "\"");

      TaskMediator(verCheckPanel, verCheckLogTextBox, messages);

      // next task
      if (0 == errMsg.Length)
      {
        downloadStageLabel.Text = "Fetching available versions information...";
        verCheckPanel.Update();

        bool res = false;

        try
        {
          res= pluginBE.fetch_release_info();
        }
        catch(System.Exception)
        {
          messages.Add("Internal plugin error during fetching available versions information.");
        }

        if (!res)
        {
          messages.Add("Failed to fetch information on available versions. For more details look into log files in temp dir.");
          errMsg = "-"; // suppress wizard err message box
          fetchRelInfoLabel.TaskState = MySQLTaskStatusLabelState.TaskError;
        }
        else
          fetchRelInfoLabel.TaskState = MySQLTaskStatusLabelState.TaskCompleted;
      }
      else
        fetchRelInfoLabel.TaskState = MySQLTaskStatusLabelState.TaskError;

      TaskMediator(verCheckPanel, verCheckLogTextBox, messages);

      // next task
      if (0 == errMsg.Length)
      {
        ResetCombo(releaseCombo, pluginBE.rel_names());

        checkVerLabel.TaskState = MySQLTaskStatusLabelState.TaskCompleted;
      }
      else
        checkVerLabel.TaskState = MySQLTaskStatusLabelState.TaskError;

      TaskMediator(verCheckPanel, verCheckLogTextBox, messages);

      StepEpilog(errMsg, verCheckResultLabel, verCheckStageLabel);

      return errMsg;
    }

    private void releaseCombo_SelectedIndexChanged(object sender, EventArgs e)
    {
      if (-1 < releaseCombo.SelectedIndex)
        ResetCombo(mirrorCombo, pluginBE.download_mirrors(releaseCombo.SelectedIndex));
      else
        mirrorCombo.Items.Clear();
    }

    private string CleanupVerCheckPage()
    {
      verCheckLogTextBox.Text = "";
      return "";
    }

    private string ProcessVerCheckPage()
    {
      String errMsg = "";
      if (-1 == releaseCombo.SelectedIndex)
        errMsg = "Select target release version please.";
      else if (-1 == mirrorCombo.SelectedIndex)
        errMsg = "Select download mirror please.";
      return errMsg;
    }
#endregion VerCheck


#region Download
    private string InitializeDownloadPage()
    {
      List<String> messages = new List<String>();
      string errMsg = "";

      downloadUpdateLabel.TaskState = MySQLTaskStatusLabelState.TaskOpen;
      runInstallLabel.TaskState = MySQLTaskStatusLabelState.TaskOpen;
      StepProlog(downloadResultLabel, downloadStageLabel);

      cancelDownloadBtn.Enabled = false;
      downloadCancelled = false;

      downloadProgressDetailsLabel.Text = "";
      downloadProgressBar.Minimum = 0;
      downloadProgressBar.Maximum = 100;

      // initialization task
      downloadSucceeded = true;
      pluginBE.task_msg_cb(ProcessDownloadMsg);
      pluginBE.task_progress_cb(ProcessDownloadProgress);
      pluginBE.task_fail_cb(ProcessDownloadFail);
      pluginBE.task_finish_cb(ProcessDownloadFinish);

      wizard.SkipRestoreControlsStateOnce();

      // notes
      messages.Add("Note: additional log files will be stored in \"" + pluginBE.working_dir() + "\"");

      TaskMediator(downloadPanel, downloadLogTextBox, messages);

      // next task
      if (0 == errMsg.Length)
      {
        downloadStageLabel.Text = "Downloading new version...";
        downloadPanel.Update();

        if (-1 != releaseCombo.SelectedIndex)
        {
          pluginBE.start_download(releaseCombo.SelectedIndex, mirrorCombo.SelectedIndex);
          cancelDownloadBtn.Enabled = true;
        }
        else
        {
          messages.Add("Target release was not set.");
          errMsg = "-"; // suppress wizard err message box
          downloadUpdateLabel.TaskState = MySQLTaskStatusLabelState.TaskError;
        }
      }
      else
        downloadUpdateLabel.TaskState = MySQLTaskStatusLabelState.TaskError;

      TaskMediator(downloadPanel, downloadLogTextBox, messages);

      return errMsg;
    }

    private string CleanupDownloadPage()
    {
      downloadLogTextBox.Text = "";
      return "";
    }

    private int ProcessDownloadMsg(int msgType, String message)
    {
      if ((Msg_type)msgType == Msg_type.MT_error)
        downloadSucceeded = false;
      downloadLogTextBox.Text += message + System.Console.Out.NewLine;
      downloadLogTextBox.Update();
      return 0;
    }

    private int ProcessDownloadProgress(float progressState, String message)
    {
      downloadProgressBar.Value = (int)(progressState * (float)100);
      downloadProgressDetailsLabel.Text = message;

      downloadProgressBar.Update();
      downloadProgressDetailsLabel.Update();
      
      return 0;
    }

    private int ProcessDownloadFail(String message)
    {
      cancelDownloadBtn.Enabled = false;

      downloadLogTextBox.Text += downloadCancelled ? "Download was cancelled." : message;
      downloadLogTextBox.Update();

      downloadUpdateLabel.TaskState = MySQLTaskStatusLabelState.TaskError;
      runInstallLabel.TaskState = MySQLTaskStatusLabelState.TaskError;

      if (0 < message.Length)
        message = "-"; // suppress wizard err message box
      StepEpilog(message, downloadResultLabel, downloadStageLabel);
      wizard.RestoreControlsState(message);
      return 0;
    }

    private int ProcessDownloadFinish()
    {
      cancelDownloadBtn.Enabled = false;

      List<String> messages = new List<String>();
      String errMsg = "";

      if (!downloadSucceeded)
        errMsg = downloadCancelled ? "Download was cancelled." :
          "Failed to download new version. For more details look into log files in temp dir.";

      MySQLTaskStatusLabelState taskStatus = downloadSucceeded
        ? MySQLTaskStatusLabelState.TaskCompleted : MySQLTaskStatusLabelState.TaskError;
      downloadUpdateLabel.TaskState = taskStatus;

      if (downloadSucceeded)
      {
        messages.Add("Ready to start installation of new version.");
        messages.Add("Press \"Finish\" to close current application instance and run installation.");
      }
      else
        runInstallLabel.TaskState = taskStatus;

      TaskMediator(downloadPanel, downloadLogTextBox, messages);

      wizard.RestoreControlsState(errMsg);
      return 0;
    }

    private void cancelDownloadBtn_Click(object sender, EventArgs e)
    {
      pluginBE.cancel_download();
      downloadCancelled = true;
    }

    private String ProcessDownloadPage()
    {
      List<String> messages = new List<String>();
      String errMsg = "";

      bool installStarted = false;

      if (downloadSucceeded)
      {
        // next task (run installation)
        downloadStageLabel.Text = "Running installation...";
        downloadLogTextBox.Text += downloadStageLabel.Text + System.Console.Out.NewLine;
        downloadPanel.Update();

        if (pluginBE.install())
        {
          installStarted = true;
          runInstallLabel.TaskState = MySQLTaskStatusLabelState.TaskCompleted;
        }
        else
        {
          messages.Add("Failed to run installation \"" + pluginBE.result_filepath() + "\".");
          errMsg = "-"; //! suppress wizard err message box
          runInstallLabel.TaskState = MySQLTaskStatusLabelState.TaskError;
        }
      }

      StepEpilog(errMsg, downloadResultLabel, downloadStageLabel);

      if (installStarted)
      {
        Form mainForm = null;
        foreach (Form form in Application.OpenForms)
        {
          if (!form.Modal && (form.TopLevelControl is Form))
          {
            mainForm = form.TopLevelControl as Form;
            break;
          }
        }
        if (null != mainForm)
          mainForm.Close();
      }

      return errMsg;
    }
#endregion Download
  }
}