//
// LameLogin.cs
//
// Copyright (c) 2007 Lukas Lipka.
//

using System;
using System.Collections.Generic;
using System.Text;

using IcqSharp.Packets;
using IcqSharp.Util;

namespace IcqSharp.Connections
{
    public class LameLogin : LoginConnection
    {
        // These are the magic bytes we roast the password against
        // using simple XOR operation
        private static byte[] roast = new byte[] {0xF3, 0x26, 0x81, 0xC4, 0x39, 0x86, 0xDB, 0x92, 0x71, 0xA3, 0xB9, 0xE6, 0x53, 0x7A, 0x95, 0x7C};

        private bool have_srv_hello = false;

        public LameLogin (Session session, string uin, string password)
            : base (session, uin, password)
        {
        }

        protected override void HandleData (byte[] data)
        {
            FlapPacket packet = null;

            try
            {
                packet = FlapPacket.Parse(data);
            }
            catch (Exception e)
            {
                Log.Error("Failed to parse login FlapPacket");
                Log.Error(e);
                return;
            }

            if (packet.Channel != 0x01 && packet.Channel != 0x04)
                Log.Error ("Invalid channel for login packet");

            // Read the hello packet from the server first before doing
            // the identification itself
            if (!have_srv_hello && BigEndianBitConverter.Big.ToInt32 (packet.Data, 0) == 0x00000001) {
                have_srv_hello = true;

                FlapPacket cip = ClientIdentification (Uin, Password);
                cip.SetSequence(Session.GetSequenceNumber());
                Write (cip.Write ());

                return;
            }

            // Now we have the hello packet and have requested authentication
            // so we are expecting the cookie from the server or failure :-(
            if (packet.Channel == 0x04)
            {
                TlvList tlvs = TlvList.Parse (packet.Data);

                // If we are banned and don't receive the cookie there won't be
                // a screenname TLV, instead this contains the screenname length
                // followed by the screename
                if (tlvs [0x0008] != null)
                {
                    ushort error_code = tlvs[0x0008].ToUInt16();
                    Log.Error(Errors.GetError (error_code));
                    
                    // We won't get past this - so disconnect
                    //Disconnect();

                    OnLoginFailed(null, EventArgs.Empty);

                    return;
                }

                // FIXME: Fix a case when we enter incorrect UIN/password

                string uin = tlvs [0x0001].ToString ();
                string server = tlvs [0x0005].ToString ();
                byte[] cookie = tlvs[0x0006].Data;

                Log.Debug ("Got cookie for {1}", uin);

                GotCookie (uin, server, cookie);

                // Finished - we have the cookie so disconnect
                Disconnect ();
            }
        }

        private FlapPacket ClientIdentification (string username, string password)
        {
            byte[] roasted_password = RoastPassword (password);

            FlapPacket f = new FlapPacket (0x01, 0x0007, null);
            f.AddDword (0x00000001);
            f.AddTlv (new Tlv (0x0001, username));
            f.AddTlv (new Tlv (0x0002, roasted_password));

            return f;
        }

        public static byte[] RoastPassword (string password)
        {
            byte[] data = System.Text.Encoding.UTF8.GetBytes (password);

            for (int i = 0; i < data.Length; i++)
                data[i] = (byte)(data[i] ^ roast[i]);

            return data;
        }
    }
}
