using System;
using System.Windows.Forms;
using CityOfHeroes;

namespace ExtendScannerWinForms_CS
{
   /// <summary>
   /// Demo class for using the scanner in your own application.
   /// 
   /// Note that this project has a post-build event that copies ChatMessageregexs.dat
   /// into the run directory. That file needs to be in the same directory as the
   /// executable in order to get the regular expressions that the ChatMessage class
   /// uses to parse the messages that come in from the CoH client.
   /// </summary>
   public class MainForm : System.Windows.Forms.Form
    {
      private System.Windows.Forms.MainMenu mainMenu1;
      private System.Windows.Forms.MenuItem miFile;
      private System.Windows.Forms.MenuItem miFileExit;
      private System.Windows.Forms.MenuItem miScanner;
      private System.Windows.Forms.MenuItem miScannerStart;
      private System.Windows.Forms.MenuItem miScannerStop;
      private System.Windows.Forms.Panel pnlLeft;
      private System.Windows.Forms.Splitter splitter1;
      private System.Windows.Forms.Panel pnlRight;
      private System.Windows.Forms.Label label1;
      private System.Windows.Forms.Label label2;
      private System.Windows.Forms.MenuItem menuItem6;
      private System.Windows.Forms.MenuItem miScannerPause;
      private System.Windows.Forms.MenuItem miScannerResume;
      private System.Windows.Forms.ListBox lbStatus;
      private System.Windows.Forms.ListBox lbMessages;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

      // our scanner object
      private CityOfHeroes.Scanner.CohScanner scanner;

        public MainForm()
        {
            InitializeComponent();

         // first, instantiate the scanner object
         scanner = new CityOfHeroes.Scanner.CohScanner();

         // now initialize the chat message subsystem. Note that these last two 
         // items don't have to be done in this order
         //
         // Also note that, strictly speaking, this doesn't have to be called. If
         // you fail to do so, the chat message subsystem will initialize the first
         // time it's needed. Unfortunately, that can take some time (up to 10 seconds
         // or so), so it's better to initialize it up front when you're doing the rest
         // of your application setup so as to not have an ugly pause in the processing
         // of your first chat message
         CityOfHeroes.ChatMessage.Initialize();

         // by default, the scanner will scan the chat channels that contain the 
         // information it needs. You can add additional channels as desired
         //
         // e.g., Broadcast is not selected by default, but let's get its messages too.
         scanner.BroadcastChannel = true;

         // now let's register for some events
         scanner.OnHeroLogin += new CityOfHeroes.Scanner.HeroLoginHandler(scanner_OnHeroLogin);
         scanner.OnHeroLogout += new CityOfHeroes.Scanner.HeroLogoutHandler(scanner_OnHeroLogout);
         scanner.OnScanningError += new CityOfHeroes.Scanner.ScanningErrorHandler(scanner_OnScanningError);
         scanner.OnScanningPaused += new CityOfHeroes.Scanner.ScanningInactiveHandler(scanner_OnScanningPaused);
         scanner.OnScanningResumed += new CityOfHeroes.Scanner.ScanningActiveHandler(scanner_OnScanningResumed);
         scanner.OnScanningStart += new CityOfHeroes.Scanner.ScanningStartHandler(scanner_OnScanningStart);
         scanner.OnScanningStop += new CityOfHeroes.Scanner.ScanningStopHandler(scanner_OnScanningStop);
         scanner.OnChatMessage += new CityOfHeroes.Scanner.ChatMessageEventHandler(scanner_OnChatMessage);

         // and we're ready to start the scanner. Note that this is a user action in this
         // application, under the 'Scanner' submenu
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
         this.mainMenu1 = new System.Windows.Forms.MainMenu();
         this.miFile = new System.Windows.Forms.MenuItem();
         this.miFileExit = new System.Windows.Forms.MenuItem();
         this.miScanner = new System.Windows.Forms.MenuItem();
         this.miScannerStart = new System.Windows.Forms.MenuItem();
         this.miScannerStop = new System.Windows.Forms.MenuItem();
         this.pnlLeft = new System.Windows.Forms.Panel();
         this.splitter1 = new System.Windows.Forms.Splitter();
         this.pnlRight = new System.Windows.Forms.Panel();
         this.label1 = new System.Windows.Forms.Label();
         this.label2 = new System.Windows.Forms.Label();
         this.lbStatus = new System.Windows.Forms.ListBox();
         this.lbMessages = new System.Windows.Forms.ListBox();
         this.menuItem6 = new System.Windows.Forms.MenuItem();
         this.miScannerPause = new System.Windows.Forms.MenuItem();
         this.miScannerResume = new System.Windows.Forms.MenuItem();
         this.pnlLeft.SuspendLayout();
         this.pnlRight.SuspendLayout();
         this.SuspendLayout();
         // 
         // mainMenu1
         // 
         this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                                                                                  this.miFile,
                                                                                  this.miScanner});
         // 
         // miFile
         // 
         this.miFile.Index = 0;
         this.miFile.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                                                                               this.miFileExit});
         this.miFile.Text = "&File";
         // 
         // miFileExit
         // 
         this.miFileExit.Index = 0;
         this.miFileExit.Text = "E&xit";
         this.miFileExit.Click += new System.EventHandler(this.miFileExit_Click);
         // 
         // miScanner
         // 
         this.miScanner.Index = 1;
         this.miScanner.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                                                                                  this.miScannerStart,
                                                                                  this.miScannerStop,
                                                                                  this.menuItem6,
                                                                                  this.miScannerPause,
                                                                                  this.miScannerResume});
         this.miScanner.Text = "&Scanner";
         this.miScanner.Popup += new System.EventHandler(this.miScanner_Popup);
         // 
         // miScannerStart
         // 
         this.miScannerStart.Index = 0;
         this.miScannerStart.Text = "Star&t";
         this.miScannerStart.Click += new System.EventHandler(this.miScannerStart_Click);
         // 
         // miScannerStop
         // 
         this.miScannerStop.Enabled = false;
         this.miScannerStop.Index = 1;
         this.miScannerStop.Text = "Sto&p";
         this.miScannerStop.Click += new System.EventHandler(this.miScannerStop_Click);
         // 
         // pnlLeft
         // 
         this.pnlLeft.Controls.Add(this.lbStatus);
         this.pnlLeft.Controls.Add(this.label1);
         this.pnlLeft.Dock = System.Windows.Forms.DockStyle.Left;
         this.pnlLeft.Location = new System.Drawing.Point(0, 0);
         this.pnlLeft.Name = "pnlLeft";
         this.pnlLeft.Size = new System.Drawing.Size(240, 350);
         this.pnlLeft.TabIndex = 0;
         // 
         // splitter1
         // 
         this.splitter1.Location = new System.Drawing.Point(240, 0);
         this.splitter1.Name = "splitter1";
         this.splitter1.Size = new System.Drawing.Size(6, 350);
         this.splitter1.TabIndex = 1;
         this.splitter1.TabStop = false;
         // 
         // pnlRight
         // 
         this.pnlRight.Controls.Add(this.lbMessages);
         this.pnlRight.Controls.Add(this.label2);
         this.pnlRight.Dock = System.Windows.Forms.DockStyle.Fill;
         this.pnlRight.Location = new System.Drawing.Point(246, 0);
         this.pnlRight.Name = "pnlRight";
         this.pnlRight.Size = new System.Drawing.Size(258, 350);
         this.pnlRight.TabIndex = 2;
         // 
         // label1
         // 
         this.label1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
         this.label1.Dock = System.Windows.Forms.DockStyle.Top;
         this.label1.Location = new System.Drawing.Point(0, 0);
         this.label1.Name = "label1";
         this.label1.Size = new System.Drawing.Size(240, 23);
         this.label1.TabIndex = 0;
         this.label1.Text = "Status";
         this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
         // 
         // label2
         // 
         this.label2.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
         this.label2.Dock = System.Windows.Forms.DockStyle.Top;
         this.label2.Location = new System.Drawing.Point(0, 0);
         this.label2.Name = "label2";
         this.label2.Size = new System.Drawing.Size(258, 23);
         this.label2.TabIndex = 0;
         this.label2.Text = "Chat Messages";
         this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
         // 
         // lbStatus
         // 
         this.lbStatus.Dock = System.Windows.Forms.DockStyle.Fill;
         this.lbStatus.IntegralHeight = false;
         this.lbStatus.Location = new System.Drawing.Point(0, 23);
         this.lbStatus.Name = "lbStatus";
         this.lbStatus.ScrollAlwaysVisible = true;
         this.lbStatus.Size = new System.Drawing.Size(240, 327);
         this.lbStatus.TabIndex = 1;
         // 
         // lbMessages
         // 
         this.lbMessages.Dock = System.Windows.Forms.DockStyle.Fill;
         this.lbMessages.IntegralHeight = false;
         this.lbMessages.Location = new System.Drawing.Point(0, 23);
         this.lbMessages.Name = "lbMessages";
         this.lbMessages.ScrollAlwaysVisible = true;
         this.lbMessages.Size = new System.Drawing.Size(258, 327);
         this.lbMessages.TabIndex = 1;
         // 
         // menuItem6
         // 
         this.menuItem6.Index = 2;
         this.menuItem6.Text = "-";
         // 
         // miScannerPause
         // 
         this.miScannerPause.Enabled = false;
         this.miScannerPause.Index = 3;
         this.miScannerPause.Text = "&Pause";
         this.miScannerPause.Click += new System.EventHandler(this.miScannerPause_Click);
         // 
         // miScannerResume
         // 
         this.miScannerResume.Enabled = false;
         this.miScannerResume.Index = 4;
         this.miScannerResume.Text = "&Resume";
         this.miScannerResume.Click += new System.EventHandler(this.miScannerResume_Click);
         // 
         // MainForm
         // 
         this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
         this.ClientSize = new System.Drawing.Size(504, 350);
         this.Controls.Add(this.pnlRight);
         this.Controls.Add(this.splitter1);
         this.Controls.Add(this.pnlLeft);
         this.Menu = this.mainMenu1;
         this.Name = "MainForm";
         this.Text = "HeroStats Scanner Extension";
         this.pnlLeft.ResumeLayout(false);
         this.pnlRight.ResumeLayout(false);
         this.ResumeLayout(false);

      }
        #endregion

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() 
        {
            Application.Run(new MainForm());
        }

      #region Form Event Handlers
      private void miFileExit_Click(object sender, System.EventArgs e)
      {
         Close();
      }

      private void miScannerStart_Click(object sender, System.EventArgs e)
      {
         scanner.Start();
      }

      private void miScannerStop_Click(object sender, System.EventArgs e)
      {
         scanner.Stop();
      }

      private void miScannerPause_Click(object sender, System.EventArgs e)
      {
         scanner.Pause();
      }

      private void miScannerResume_Click(object sender, System.EventArgs e)
      {
         scanner.Resume();
      }

      private void miScanner_Popup(object sender, System.EventArgs e)
      {
         miScannerStart.Enabled = !scanner.Scanning;
         miScannerStop.Enabled = scanner.Scanning;
         miScannerPause.Enabled = scanner.Scanning && !scanner.Paused;
         miScannerResume.Enabled = scanner.Scanning && scanner.Paused;
      }
      #endregion

      #region Scanner Event Handlers
      /***********************************************************
       * Below are the event handlers for the scanner.
       * 
       * Note that these will always be called on a thread that is
       * different from the UI's thread. Due to the way .NET event
       * handling works for UI elements, if you're handling a message
       * on a thread that's not the UI thread, you must call Invoke
       * on the control in order to switch to the UI thread prior to
       * doing any action with the UI.
       * 
       * That's why you'll see a check for InvokeRequired and the
       * call to Invoke in each one of these. The good news is that,
       * since they're already event handlers, there's delegates set up
       * for them, so you don't have to create new delegates to pass off
       * to Invoke()
       ***********************************************************/

      /// <summary>
      /// Handles an event that gets fired when a new hero logs into CoH
      /// </summary>
      /// <param name="hero">Information about the hero logging in</param>
      private void scanner_OnHeroLogin(CityOfHeroes.HeroData hero)
      {
         if (InvokeRequired)
            Invoke(new CityOfHeroes.Scanner.HeroLoginHandler(scanner_OnHeroLogin));
         else
         {
            lbStatus.Items.Add(string.Format("Hero '{0}' just logged in", hero.Name));
         }
      }

      /// <summary>
      /// Handles an event that gets fired when a new hero logs out of CoH
      /// </summary>
      /// <param name="hero">Information about the hero logging out</param>
      private void scanner_OnHeroLogout(CityOfHeroes.HeroData hero)
      {
         if (InvokeRequired)
            Invoke(new CityOfHeroes.Scanner.HeroLogoutHandler(scanner_OnHeroLogout));
         else
         {
            lbStatus.Items.Add(string.Format("Hero '{0}' just logged out", hero.Name));
         }
      }

      /// <summary>
      /// Handles an event that gets fired when an error occurs in the scanner
      /// </summary>
      /// <param name="msg">Details of the error. Also stored in CohScanner.Error</param>
      private void scanner_OnScanningError(string msg)
      {
         if (InvokeRequired)
            Invoke(new CityOfHeroes.Scanner.ScanningErrorHandler(scanner_OnScanningError));
         else
         {
            lbStatus.Items.Add(string.Format("A scanning error occurred. {0}", msg));
         }
      }

      /// <summary>
      /// Handles an event that gets fired when the scanner is programmatically paused
      /// </summary>
      private void scanner_OnScanningPaused()
      {
         if (InvokeRequired)
            Invoke(new CityOfHeroes.Scanner.ScanningInactiveHandler(scanner_OnScanningPaused));
         else
         {
            lbStatus.Items.Add("The scanner has been paused");
         }
      }

      /// <summary>
      /// Handles an event that gets fired when the scanner is programmatically resumed
      /// after a pause
      /// </summary>
      private void scanner_OnScanningResumed()
      {
         if (InvokeRequired)
            Invoke(new CityOfHeroes.Scanner.ScanningActiveHandler(scanner_OnScanningResumed));
         else
         {
            lbStatus.Items.Add("Scanning is resumed");
         }
      }

      /// <summary>
      /// Handles an event that gets fired when the scanner has started. Its first action
      /// is to try to find the CoH client. Once it finds it, it switches to reading the
      /// chat messages. Note that both of these activities are termed "scanning"
      /// </summary>
      private void scanner_OnScanningStart()
      {
         if (InvokeRequired)
            Invoke(new CityOfHeroes.Scanner.ScanningStartHandler(scanner_OnScanningStart));
         else
         {
            lbStatus.Items.Add("The scanner has been started");
         }
      }

      /// <summary>
      /// Handles an event that gets fired when the scanner has been told to stop scanning.
      /// </summary>
      private void scanner_OnScanningStop()
      {
         if (InvokeRequired)
            Invoke(new CityOfHeroes.Scanner.ScanningStopHandler(scanner_OnScanningStop));
         else
         {
            lbStatus.Items.Add("The scanner has been stopped");
         }
      }

      /// <summary>
      /// Handles an event that gets fired when a chat message has been detected.
      /// </summary>
      /// <param name="message">The incoming message</param>
      private void scanner_OnChatMessage(CityOfHeroes.ChatMessage message)
      {
         if (InvokeRequired)
            Invoke(new CityOfHeroes.Scanner.ChatMessageEventHandler(scanner_OnChatMessage));
         else
         {
            lbMessages.Items.Add(string.Format("ChatMessage from {0} at {1}: {2}", message.Channel, message.Timestamp, message.Message));
            lbMessages.Items.Add(string.Format("   Category: {0}", message.Category));
         }
      }
      #endregion

   }
}