// GUIBridge.cs
// Copyright (C) 2002 Matt Zyzik (www.FileScope.com)
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

using System;
using System.Diagnostics;
using System.Threading;
using FileScope.Gnutella2;
using ZANZILib;

namespace FileScope
{
    /// <summary>
    /// Class used as a bridge between the backend core and the frontend gui.
    /// Almost everything is done via Invoke so that the GUI thread takes care of everything on its own.
    /// This class is the ONLY way the core can even touch the gui.
    /// </summary>
    public class GUIBridge
    {
        // delegate declaration

        #region Delegates

        public delegate void G2JustConnectedDelegate(int sockNum);

        public delegate void G2JustDisconnectedeDelegate(int sockNum);

        ////zzoi 29feb 2009
        public delegate void G2QueryHitDelegate(QueryHitObject qho, QueryHitTable qht,  string searchName);

        //public delegate void NetworkStatusDelegate(string networkstatus);
        
        public delegate void G2NewConnectionDelegate(string addr, int sockNum);

        public delegate void G2UpdateDelegate(int sockNum, string bwInOut);

        public delegate void NewChatDataDelegate(int chatnum, string str);

        public delegate void NewChatDelegate(int chatnum);

        public delegate void NewHostCacheDelegate(int index);

        public delegate void NewHostCacheDeleteDelegate(string key);

        public delegate void NewWebCacheDelegate(int index); // delegate declaration
        public delegate void NewWebCacheDeleteDelegate(string key);

        public delegate void NewDownloadDelegate(QueryHitTable qht, int dlNum);
        public delegate void RemoveDownloadDelegate( int dlNum);

        public delegate void UpdateDownloadDelegate(ref string status, ref string percent, ref string speed, int dlNum);

        #endregion

        public static event NewChatDelegate NewChatEvent;
        public static event NewChatDelegate ConnectedChatEvent;
        public static event NewChatDelegate DisconnectedChatEvent;
        public static event NewChatDataDelegate NewChatDataEvent;

        public static event NewWebCacheDelegate NewWebCacheRecord;
        public static event NewWebCacheDelegate UpdateWebCacheRecord;
        //public static event  NewWebCacheDeleteDelegate DeleteWebCacheRecord;

        public static event NewHostCacheDelegate NewHostCacheRecord;
        public static event NewHostCacheDelegate UpdateHostCacheRecord;
        public static event NewHostCacheDeleteDelegate DeleteHostCacheRecord;

        public static event G2NewConnectionDelegate G2NewConnectionEvent;
        public static event G2JustConnectedDelegate G2JustConnectedEvent;
        public static event G2UpdateDelegate G2UpdateEvent;
        public static event G2JustDisconnectedeDelegate G2JustDisconnectedeEvent;

        //zzoi 10mrt 2009
        public static event NewDownloadDelegate NewDownloadEvent;
        public static event RemoveDownloadDelegate RemoveDownloadEvent;
        public static event UpdateDownloadDelegate UpdateDownloadEvent;

        //public static event G2QueryHitDelegate G2QueryHitEvent;

        //zzoi 28 Feb 2009 added event to see queryhits in syslog
        public static event G2QueryHitDelegate G2QueryHitEvent;
        //zzoi 9 mrt 2009 network status update
        //public static event NetworkStatusDelegate NetworkStatusEvent;

        #region NetWork Engen

        #region Delegates

        public delegate void NetworkStatusDelegate(string key);

        #endregion

        public static event NetworkStatusDelegate NetworkStatusChange;

        #endregion


        /// <summary>
        /// Inform GUI of a new incoming QueryHit.
        /// </summary>
        public static void AddQueryHit(QueryHitObject qho, QueryHitTable qht,  string searchName)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                //dont have attached event handlers

                //zzoi 29feb 2009
                if (G2QueryHitEvent != null)
                {
                    G2QueryHitEvent(qho, qht, searchName);
                }

                //BUG
                //zzoi 14mrt 2009
                //the filesize, filepath , ip, ipepNH, longip is wrong
                //this prevent the download from the qui to suceed

                //clsMain.RaiseSystemMessage("G2QueryHitEvent" + Sck.scks[sockNum].address);
                clsMain.RaiseSystemMessage("G2QueryHitEvent " + qho.ip +" " + qho.port );

                //zzoi debug view the result xml in syslog
                clsMain.RaiseSystemMessage("QueryHit string recieved : " + qho.xml);
                
            //}
            //catch
            //{
            //    Debug.WriteLine("guibridge AddQueryHitTable");
            //}



            //if (Stats.Updated.closing)
            //    return;
            //try
            //{
            //    //we're trying to find the tabpage for this corresponding search
            //    foreach (searchtabpage tabpage in startapp.main.search.tabcontrol1.tabpages)
            //    {
            //        if (searchname.length >= 8 && searchname.substring(0, 8) == "browse: ")
            //        {
            //            if (tabpage.tag.tostring().indexof(searchname) != -1)
            //            {
            //                tabpage.begininvoke(new searchtabpage.addnewitem(tabpage.addnewitem), new object[] { qho, qht });
            //                return;
            //            }
            //        }
            //        else if (tabpage.tag.tostring() == searchname)
            //        {
            //            tabpage.begininvoke(new searchtabpage.addnewitem(tabpage.addnewitem), new object[] { qho, qht });
            //            return;
            //        }
            //    }

                //clsMain.RaiseSystemMessage("G2QueryHitEvent" + Sck.scks[sockNum].address);
                clsMain.RaiseSystemMessage("G2QueryHitEvent" + qho.ip + " " + qho.port);
            }
            catch
            {
                System.Diagnostics.Debug.WriteLine("guibridge AddQueryHitTable");
            }
        }

        public static void RefreshHomePageNetworks()
        {
//			if(StartApp.main == null)
//				return;
            //if(Stats.Updated.closing)
            //	return;
            try
            {
                //zzoi 9 june 2008 once connected raise event to gui to reset the visual connection status in the Client
                NetworkStatusChange(ConnectionManager.status);


                //StartApp.main.homepage.BeginInvoke(new HomePage.resetNetworksText(StartApp.main.homepage.ResetNetworksText));


//				//gnutella 2
//				string gnutella2Stat = "Connected";
//				if(Stats.Updated.Gnutella2.lastConnectionCount == 0)
//					gnutella2Stat = Gnutella2.ConnectionManager.status;
//				lbl2Network2.Text = "      Gnutella2: " + gnutella2Stat;
//				if(gnutella2Stat == "Connected")
//					lbl2Network2.Text += "(" + Stats.Updated.Gnutella2.lastConnectionCount.ToString() + ")";
//				if(Gnutella2.ConnectionManager.status == "Disconnected")
//				{
//					lbl2Network2.Text += " --- Connect";
//					lbl2Network2.LinkArea = new LinkArea(lbl2Network2.Text.Length - 7, 7);
//				}
//				else
//				{
//					lbl2Network2.Text += " --- Disconnect";
//					lbl2Network2.LinkArea = new LinkArea(lbl2Network2.Text.Length - 10, 10);
//				}
//
            }
            catch
            {
                Debug.WriteLine("guibridge RefreshHomePageNetworks");
            }
        }

        public static void RefreshHomePageTransfers()
        {
//			if(StartApp.main == null)
//				return;
            if (Stats.Updated.closing)
                return;
            try
            {
                //StartApp.main.homepage.BeginInvoke(new HomePage.resetTransfersText(StartApp.main.homepage.ResetTransfersText));
            }
            catch
            {
                Debug.WriteLine("guibridge RefreshHomePageTransfers");
            }
        }

        public static void RefreshHomePageLibrary()
        {
//			if(StartApp.main == null)
//				return;
            if (Stats.Updated.closing)
                return;
            try
            {
                //StartApp.main.homepage.BeginInvoke(new HomePage.resetLibraryText(StartApp.main.homepage.ResetLibraryText));
            }
            catch
            {
                Debug.WriteLine("guibridge RefreshHomePageLibrary");
            }
        }

        /// <summary>
        /// New download; update UI.
        /// </summary>
        public static void NewDownload(QueryHitTable qht, int dlNum)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
//				StartApp.main.transfers.Invoke(new Transfers.newDownload(StartApp.main.transfers.NewDownload), new object[] {qht, dlNum});

                if (NewDownloadEvent != null)
                {
                    NewDownloadEvent(qht, dlNum);
                }

                clsMain.RaiseSystemMessage("FileDownloadEvent " + qht.address.ToString()+ " " +((QueryHitObject) qht.queryHitObjects[0]).fileName );
            }
            catch
            {
                Debug.WriteLine("guibridge NewDownload");
            }
        }

        /// <summary>
        /// Update the download information.
        /// </summary>
        public static void UpdateDownload(ref string status, ref string percent, ref string speed, int dlNum)
        {
            if (Stats.Updated.closing)
                return;
            try
            {

                //zzoi 10mrt 2009
                if (UpdateDownloadEvent != null)
                {
                    UpdateDownloadEvent(ref status, ref percent, ref speed, dlNum);
                }

                //clsMain.RaiseSystemMessage("G2QueryHitEvent" + Sck.scks[sockNum].address);
                clsMain.RaiseSystemMessage("UpdateDownload nr " + dlNum);

//				StartApp.main.transfers.Invoke(new Transfers.updateDownload(StartApp.main.transfers.UpdateDownload), new object[] {status, percent, speed, dlNum});
            }
            catch
            {
                Debug.WriteLine("guibridge UpdateDownload");
            }
        }

        /// <summary>
        /// A download just ended; update UI.
        /// </summary>
        public static void RemoveDownload(int dlNum)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                //zzoi 14mrt 2009
                if (RemoveDownloadEvent != null)
                {
                    RemoveDownloadEvent( dlNum);
                }

                //clsMain.RaiseSystemMessage("G2QueryHitEvent" + Sck.scks[sockNum].address);
                clsMain.RaiseSystemMessage("RemoveDownload nr " + dlNum);
            }
            catch (Exception e)
            {
                Debug.WriteLine("guibridge RemoveDownload: " + e.Message);
                Debug.WriteLine(e.StackTrace);
            }
        }

        /// <summary>
        /// New upload.
        /// </summary>
        public static void NewUpload(int upNum)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
//				StartApp.main.transfers.Invoke(new Transfers.newUpload(StartApp.main.transfers.NewUpload), new object[] {upNum});
            }
            catch
            {
                Debug.WriteLine("guibridge NewUpload");
            }
        }

        /// <summary>
        /// Update the UI about this upload.
        /// </summary>
        public static void UpdateUpload(string filename, uint filesize, string status, string percent, string offsets,
                                        string speed, int upNum)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
//				StartApp.main.transfers.Invoke(new Transfers.updateUpload(StartApp.main.transfers.UpdateUpload), new object[] {filename, filesize, status, percent, offsets, speed, upNum});
            }
            catch
            {
                Debug.WriteLine("guibridge UpdateUpload");
            }
        }

        /// <summary>
        /// Upload just finished.
        /// </summary>
        public static void RemoveUpload(int upNum, int type)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
//				StartApp.main.transfers.Invoke(new Transfers.removeUpload(StartApp.main.transfers.RemoveUpload), new object[] {upNum, type});
            }
            catch
            {
                Debug.WriteLine("guibridge RemoveUpload");
            }
        }

        /// <summary>
        /// Notify gui of incoming G2 search.
        /// </summary>
        public static void QueryG2(ref string query)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
//				if(FileScope.MainDlg.selectedIndexMain == 1)
//					StartApp.main.connection.BeginInvoke(new Connection.g2Query(StartApp.main.connection.G2Query), new object[] {query});
            }
            catch (ThreadAbortException )
            {
                //e = e;
            }
            catch
            {
                Debug.WriteLine("Error guibridge QueryG2");
            }
        }

        /// <summary>
        /// There was a change in the shared content, modify library accordingly.
        /// </summary>
        public static void ChangeShared()
        {
            if (Stats.Updated.closing)
                return;
//			if(StartApp.main == null)
//				return;
            try
            {
                //StartApp.main.library.Invoke(new Library.updateShares(StartApp.main.library.UpdateShares));
            }
            catch
            {
                Debug.WriteLine("guibridge ChangeShared");
            }
        }


        /// <summary>
        /// Switched mode from ultrapeer to leafnode or vice-versa.
        /// </summary>
        public static void SwitchedMode()
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                //StartApp.main.connection.Invoke(new Connection.updateUltrapeerStatus(StartApp.main.connection.UpdateUltrapeerStatus));
            }
            catch
            {
                Debug.WriteLine("guibridge SwitchedMode");
            }
        }

        #region ChatEvents

        /// <summary>
        /// Either an incoming or outgoing chat was created.
        /// </summary>
        public static void NewChat(int chatNum, string address)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                //StartApp.main.chatpage.Invoke(new ChatPage.newChat(StartApp.main.chatpage.NewChat), new object[] {chatNum});
                NewChatEvent(chatNum);
                clsMain.RaiseSystemMessage("NewChat " + chatNum + " [" + address + "]");
            }
            catch (Exception)
            {
                Debug.WriteLine("Error guibridge NewChat");
            }
        }

        /// <summary>
        /// An outgoing chat has just completed its handshake.
        /// </summary>
        public static void ConnectedChat(int chatNum)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                //StartApp.main.chatpage.Invoke(new ChatPage.connectedChat(StartApp.main.chatpage.ConnectedChat), new object[] {chatNum});
                ConnectedChatEvent(chatNum);
                clsMain.RaiseSystemMessage("ConnectedChat " + chatNum);
            }
            catch
            {
                Debug.WriteLine("guibridge ConnectedChat");
            }
        }

        /// <summary>
        /// We've received a chat message from our peer.
        /// </summary>
        public static void NewChatData(int chatNum, string msg)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                //	StartApp.main.chatpage.Invoke(new ChatPage.newChatData(StartApp.main.chatpage.NewChatData), new object[] {chatNum, msg});
                NewChatDataEvent(chatNum, msg);
                clsMain.RaiseSystemMessage("NewChatData " + chatNum);
            }
            catch
            {
                Debug.WriteLine("guibridge NewChatData");
            }
        }

        /// <summary>
        /// Either an incoming or outgoing chat was finished.
        /// </summary>
        public static void DisconnectedChat(int chatNum)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                //StartApp.main.chatpage.Invoke(new ChatPage.disconnectedChat(StartApp.main.chatpage.DisconnectedChat), new object[] {chatNum});
                DisconnectedChatEvent(chatNum);
                //SystemLogMessageEventx("DisconnectedChat " + chatNum);
                clsMain.RaiseSystemMessage("DisconnectedChat " + chatNum);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                Debug.WriteLine("Error guibridge DisconnectedChat");
            }
        }

        #endregion

        #region webCache Events

        /// <summary>
        /// sends the changed record to the GUI for refresh
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="sockNum"></param>
        public static void WebCacheRecordChange(int index)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                UpdateWebCacheRecord(index);
                //ZANZILib.clsMain.RaiseSystemMessage("G2NewConnection " + addr );
            }
            catch (Exception e)
            {
                Debug.WriteLine("guibridge WebCacheRecordChange " + e.Message);
            }
        }

        /// <summary>
        /// Sends the record to be deleted
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="sockNum"></param>
        public static void WebCacheRecordDeleted(string name)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                //DeleteWebCacheRecord(name);
                //ZANZILib.clsMain.RaiseSystemMessage("G2NewConnection " + addr );
            }
            catch (Exception e)
            {
                Debug.WriteLine("guibridge WebCacheRecordDeleted " + e.Message);
            }
        }

        /// <summary>
        /// Adds a new record to the list
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="sockNum"></param>
        public static void WebCacheRecordAdd(int index)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                NewWebCacheRecord(index);

                //ZANZILib.clsMain.RaiseSystemMessage("G2NewConnection " + addr );
            }
            catch (Exception e)
            {
                Debug.WriteLine("guibridge WebCacheRecordAdd " + e.Message);
            }
        }

        #endregion

        #region hostCache Events

        /// <summary>
        /// sends the changed record to the GUI for refresh
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="sockNum"></param>
        public static void HostCacheRecordChange(int index)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                UpdateHostCacheRecord(index);
                //ZANZILib.clsMain.RaiseSystemMessage("G2NewConnection " + addr );
            }
            catch (Exception e)
            {
                Debug.WriteLine("guibridge HostCacheRecordChange " + e.Message);
            }
        }

        /// <summary>
        /// Sends the record to be deleted
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="sockNum"></param>
        public static void HostCacheRecordDeleted(string name)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                DeleteHostCacheRecord(name);
                //ZANZILib.clsMain.RaiseSystemMessage("G2NewConnection " + addr );
            }
            catch (Exception e)
            {
                Debug.WriteLine("Error guibridge HostCacheRecordDeleted " + e.Message);
            }
        }

        /// <summary>
        /// Adds a new record to the list
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="sockNum"></param>
        public static void HostCacheRecordAdd(int index)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                NewHostCacheRecord(index);

                //ZANZILib.clsMain.RaiseSystemMessage("G2NewConnection " + addr );
            }
            catch (Exception e)
            {
                Debug.WriteLine("Error guibridge HostCacheRecordAdd " + e.Message);
            }
        }

        #endregion

        #region G2 Events

        /// <summary>
        /// We just initiated a connection to a g2 host.
        /// </summary>
        public static void G2NewConnection(string addr, int sockNum)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                //dont have attached event handlers
                if (G2NewConnectionEvent != null)
                {
                    G2NewConnectionEvent(addr, sockNum);
                }

                clsMain.RaiseSystemMessage("G2NewConnection " + addr);
                //ZANZILib.clsMain.SystemLogMessage. del = new .
            }
            catch (Exception e)
            {
                Debug.WriteLine("guibridge G2NewConnection " + e.Message);
            }
        }

        /// <summary>
        /// Handshake is complete and we're now connected to the g2 host.
        /// </summary>
        public static void G2JustConnected(int sockNum)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                if (G2JustConnectedEvent != null)
                {
                    G2JustConnectedEvent(sockNum);
                }
                clsMain.RaiseSystemMessage("G2JustConnected " + Sck.scks[sockNum].address);
                //Sck.scks[sockNum]
                //FileScope.Gnutella2.Sck.scks[sockNum].address 
 
                //zzoi 9 mrt 2009 update the GUI statusbar text
                if (NetworkStatusChange != null)
                {
                    //localize
                    NetworkStatusChange("Connected");
                }

            }
            catch (Exception e)
            {
                Debug.WriteLine("Error guibridge G2JustConnected " + e.Message);
            }
        }

        /// <summary>
        /// Update bandwidth and other stuff.
        /// </summary>
        public static void G2Update(int sckNum, ref string bIn, ref string bOut)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
//				if(FileScope.MainDlg.selectedIndexMain != 1)
//					return;

                if (G2UpdateEvent != null)
                {
                    G2UpdateEvent(sckNum, " [" + bIn + "/" + bOut + "]");
                }
                //ZANZILib.clsMain.RaiseSystemMessage("G2Update " + FileScope.Gnutella2.Sck.scks[sckNum].address + " [" + bIn + "|" + bOut  + "]"   );
            }
            catch
            {
                Debug.WriteLine("guibridge G2Update");
            }
        }

        /// <summary>
        /// We just disconnected from a g2 host.
        /// </summary>
        public static void G2JustDisconnected(int sockNum)
        {
            if (Stats.Updated.closing)
                return;
            try
            {
                if (G2JustDisconnectedeEvent != null)
                {
                    G2JustDisconnectedeEvent(sockNum);
                }
                clsMain.RaiseSystemMessage("G2JustDisconnected " + Sck.scks[sockNum].address);
            }
            catch (ThreadAbortException )
            {
                //e = e;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("guibridge G2JustDisconnected");
                Debug.WriteLine(ex.Message);
            }
        }

        #endregion


    }
}