// ProcessData.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.Collections;
using System.Diagnostics;
using ZANZILib;

namespace FileScope.Gnutella2
{
    /// <summary>
    /// Class with static functions for dealing with G2 packets.
    /// </summary>
    public class G2Data
    {
        #region Delegates

        public delegate void handleFunc(Message msg);

        #endregion

        public static Hashtable funcTable;

        /// <summary>
        /// Setup our funcTable Hashtable to have delegates to functions dealing with certain types of G2 packets.
        /// </summary>
        public static void SetupFuncTable()
        {
            if (funcTable == null)
            {
                funcTable = new Hashtable(13);
                funcTable.Add(typeof (Ping), new handleFunc(HandlePing));
                funcTable.Add(typeof (Pong), new handleFunc(HandlePong));
                funcTable.Add(typeof (LocalNodeInfo), new handleFunc(HandleLNI));
                funcTable.Add(typeof (KnownHubList), new handleFunc(HandleKHL));
                funcTable.Add(typeof (Push), new handleFunc(HandlePush));
                funcTable.Add(typeof (QueryHashTable), new handleFunc(HandleQHT));
                funcTable.Add(typeof (QueryKeyRequest), new handleFunc(HandleQKR));
                funcTable.Add(typeof (QueryKeyAnswer), new handleFunc(HandleQKA));
                funcTable.Add(typeof (Query), new handleFunc(HandleQuery));
                funcTable.Add(typeof (QueryAck), new handleFunc(HandleQueryAck));
                funcTable.Add(typeof (QueryHit), new handleFunc(HandleQueryHit));
                funcTable.Add(typeof (UserProfileRequest), new handleFunc(HandleUPR));
                funcTable.Add(typeof (UserProfileAnswer), new handleFunc(HandleUPA));
            }
        }

        /// <summary>
        /// Deal with a root packet and its children.
        /// </summary>
        public static void ProcessMessage(Message msg)
        {
#if DEBUG
            //System.Diagnostics.Debug.Assert(msg.ToString() != "FileScope.Gnutella2.Query");
            //System.Diagnostics.Debug.Assert(msg.ToString() != "FileScope.Gnutella2.QueryHit");

#endif

            ((handleFunc) funcTable[msg.GetType()])(msg);
        }

        public static void HandlePing(Message msg)
        {
            Ping ping = (Ping) msg;
            ping.Read(0);
            Stats.Updated.Gnutella2.numPI++;
            clsMain.RaiseSystemMessage(Sck.scks[msg.sockNum].address + ":" + Sck.scks[msg.sockNum].port +
                                       " Message Ping");
        }

        public static void HandlePong(Message msg)
        {
            Pong pong = (Pong) msg;
            pong.Read(0);
            Stats.Updated.Gnutella2.numPO++;
            clsMain.RaiseSystemMessage(Sck.scks[msg.sockNum].address + ":" + Sck.scks[msg.sockNum].port +
                                       " Message Pong");
        }

        public static void HandleLNI(Message msg)
        {
            LocalNodeInfo lni = (LocalNodeInfo) msg;
            lni.Read(0);
            Stats.Updated.Gnutella2.numLNI++;
            clsMain.RaiseSystemMessage(Sck.scks[msg.sockNum].address + ":" + Sck.scks[msg.sockNum].port +
                                       " Message LocalNodeInfo");
        }

        public static void HandleKHL(Message msg)
        {
            KnownHubList khl = (KnownHubList) msg;
            khl.Read(0);
            Stats.Updated.Gnutella2.numKHL++;
            clsMain.RaiseSystemMessage(Sck.scks[msg.sockNum].address + ":" + Sck.scks[msg.sockNum].port +
                                       " Message KnownHubList");
        }

        public static void HandlePush(Message msg)
        {
            Push push = (Push) msg;
            push.Read(0);
            Stats.Updated.Gnutella2.numPUSH++;
            clsMain.RaiseSystemMessage(Sck.scks[msg.sockNum].address + ":" + Sck.scks[msg.sockNum].port +
                                       " Message Push");
        }

        public static void HandleQHT(Message msg)
        {
            if (Stats.Updated.Gnutella2.ultrapeer)
            {
                QueryHashTable qht = (QueryHashTable) msg;
                //zzoi 9 june 2008 disable the read due to error in hashtable process function
                //the qht recieved is not formatted or has other erorrs
                Debug.WriteLine("zanzi not reading the qht at the moment - error in read func");
                //qht.Read(0);
            }
            else
                //Debug.WriteLine("g2 receiving qht when leaf");
            Stats.Updated.Gnutella2.numQHT++;
            clsMain.RaiseSystemMessage(Sck.scks[msg.sockNum].address + ":" + Sck.scks[msg.sockNum].port +
                                       " Message QueryHashTable");
        }

        public static void HandleQKR(Message msg)
        {
            QueryKeyRequest qkr = (QueryKeyRequest) msg;
            qkr.Read(0);
            Stats.Updated.Gnutella2.numQKR++;
            clsMain.RaiseSystemMessage(Sck.scks[msg.sockNum].address + ":" + Sck.scks[msg.sockNum].port +
                                       " Message QueryKeyRequest");
        }

        public static void HandleQKA(Message msg)
        {
            QueryKeyAnswer qka = (QueryKeyAnswer) msg;
            qka.Read(0);
            Stats.Updated.Gnutella2.numQKA++;
            clsMain.RaiseSystemMessage(Sck.scks[msg.sockNum].address + ":" + Sck.scks[msg.sockNum].port +
                                       " Message QueryKeyAnswer");
        }

        public static void HandleQuery(Message msg)
        {
            Query query = (Query) msg;
            query.Read(0);
            Stats.Updated.Gnutella2.numQ2++;
            clsMain.RaiseSystemMessage(Sck.scks[msg.sockNum].address + ":" + Sck.scks[msg.sockNum].port +
                                       " Message Query");
        }

        public static void HandleQueryAck(Message msg)
        {
            QueryAck qa = (QueryAck) msg;
            qa.Read(0);
            Stats.Updated.Gnutella2.numQA++;
            clsMain.RaiseSystemMessage(Sck.scks[msg.sockNum].address + ":" + Sck.scks[msg.sockNum].port +
                                       " Message QueryAck");
        }

        public static void HandleQueryHit(Message msg)
        {
            QueryHit qh = (QueryHit) msg;
            qh.Read(0);
            Stats.Updated.Gnutella2.numQH2++;
            clsMain.RaiseSystemMessage(Sck.scks[msg.sockNum].address + ":" + Sck.scks[msg.sockNum].port +
                                       " Message QueryHit");
        }

        public static void HandleUPR(Message msg)
        {
            UserProfileRequest upr = (UserProfileRequest) msg;
            upr.Read(0);
            clsMain.RaiseSystemMessage(Sck.scks[msg.sockNum].address + ":" + Sck.scks[msg.sockNum].port +
                                       " Message UserProfileRequest");
        }

        public static void HandleUPA(Message msg)
        {
            UserProfileAnswer upa = (UserProfileAnswer) msg;
            upa.Read(0);
            clsMain.RaiseSystemMessage(Sck.scks[msg.sockNum].address + ":" + Sck.scks[msg.sockNum].port +
                                       " Message UserProfileAnswer");
        }
    }
}