using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Wayne.ForecourtControl;

namespace SinoChemFC2PosProxy
{
    class MsgRouterMessageUtility
    {

        #region Message string generation

        /// <summary>
        /// Subscribe pump status change for all pumps
        /// </summary>
        /// <returns></returns>
        public static string SubscribePumpStatusChange()
        {
            return string.Format("2|GUEST|SUBSCRIBE|EVT_PUMP_STATUS_CHANGE_ID_*||||^");
        }

        /// <summary>
        /// Subscribe to pump delivery progress
        /// </summary>
        /// <returns></returns>
        public static string SubscribePumpDeliveryProgress()
        {
            return string.Format("2|GUEST|SUBSCRIBE|EVT_PUMP_DELIVERY_PROGRESS_ID_*||||^");
        }

        /// <summary>
        /// Generate emergency stop message
        /// </summary>
        /// <param name="fpId"></param>
        /// <returns></returns>
        public static string EmergencyStop(int fpId)
        {
            return string.Format("2|GUEST|POST|REQ_PUMP_STOP_ID_{0, 3:000}|||PA={1}|^", fpId, 1);
        }

        /// <summary>
        /// Clear stop message
        /// </summary>
        /// <param name="fpId"></param>
        public static string ClearStop(int fpId)
        {
            return string.Format("2|GUEST|POST|REQ_PUMP_CLEAR_STOP_ID_{0, 3:000}||||^", fpId);
        }

        /// <summary>
        /// Login to message rotuer
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public static string Login(string userid, string password)
        {
            return string.Format("2|GUEST|POST|REQ_SECU_LOGIN|||US={0}|PW={1}|^", userid, password);
        }

        /// <summary>
        /// Subscribe starting to apply new price change
        /// </summary>
        /// <returns></returns>
        public static string SubscribeStartingToApplyNewPriceChange()
        {
            return string.Format("2|GUEST|SUBSCRIBE|EVT_STARTING_TO_APPLY_NEW_PRICE_CHANGE||||^");
        }

        /// <summary>
        /// Subscribe to the event where a preset is entered at the forecourt
        /// </summary>
        /// <returns></returns>
        public static string SubscribeReceivePresetFromForecourt()
        {
            return string.Format("2|GUEST|SUBSCRIBE|REQ_RECEIVE_PRESET_FROM_FORECOURT_ID_*||||^");
        }

        /// <summary>
        /// Subscribe to the event when an outdoor transaction is denied
        /// </summary>
        /// <returns></returns>
        public static string SubscribeReceiveOutdoorTrxDeniedFromForecourt()
        {
            return string.Format("2|GUEST|SUBSCRIBE|REQ_RECEIVE_OUTDOOR_TRANSACTION_DENIED_ID_*||||^");
        }

        /// <summary>
        /// Subscribe to the event when an outdoor transaction is approved
        /// </summary>
        /// <returns></returns>
        public static string SubscribeReceiveOutdoorTrxApprovedFromForecourt()
        {
            return string.Format("2|GUEST|SUBSCRIBE|REQ_RECEIVE_OUTDOOR_TRANSACTION_APPROVED_ID_*||||^");
        }

        /// <summary>
        /// Subscribe to the event when an outdoor transaction is denied
        /// </summary>
        /// <returns></returns>
        public static string SubscribeReceiveOutdoorTrxAirlockFromForecourt()
        {
            return string.Format("2|GUEST|SUBSCRIBE|REQ_RECEIVE_OUTDOOR_AIRLOCK_ID_*||||^");
        }
        /// <summary>
        /// Subscribe new price change applied
        /// </summary>
        /// <returns></returns>
        public static string SubscribeNewPriceChangeApplied()
        {
            return string.Format("2|GUEST|SUBSCRIBE|EVT_NEW_PRICE_CHANGE_APPLIED||||^");
        }

        /// <summary>
        /// Subscribe set new price change response
        /// </summary>
        /// <returns></returns>
        public static string SubscribeSetNewPriceChange()
        {
            return string.Format("2|GUEST|SUBSCRIBE|RES_PRICES_SET_NEW_PRICE_CHANGE||||^");
        }

        /// <summary>
        /// Subscribe refresh price change table
        /// </summary>
        /// <returns></returns>
        public static string SubscribeRefreshPriceChangeTbl()
        {
            return string.Format("2|GUEST|SUBSCRIBE|RES_PRICES_REFRESH_PRICE_CHANGE_TBL||||^");
        }


        /// <summary>
        /// Force forecourt to load new prices
        /// </summary>
        /// <returns></returns>
        public static string LoadNewPrices()
        {
            return string.Format("2|GUEST|POST|REQ_LOAD_NEW_PRICES||||^");
        }

        /// <summary>
        /// Set new price for single grade
        /// </summary>
        /// <param name="da">Date to be processed, YYYYMMDD</param>
        /// <param name="ti">Time to be pricessed, HHMMSS</param>
        /// <param name="gradeNumber">Grade number</param>
        /// <param name="price">Grade price</param>
        /// <returns></returns>
        public static string SetNewPriceChange(string da, string ti, string gradeNumber, string price)
        {
            if (da.Length == 0 && ti.Length == 0)
                return string.Format("2|GUEST|POST|REQ_PRICES_SET_NEW_PRICE_CHANGE|||QTY=1|G01NR={0}|G01LV=1|G01PR={1}|^",
                                    gradeNumber, price);
            else
                return string.Format("2|GUEST|POST|REQ_PRICES_SET_NEW_PRICE_CHANGE|||DA={0}|TI={1}|QTY=1|G01NR={2}|G01LV=1|G01PR={3}|^",
                                    da, ti, gradeNumber, price);
        }

        /// <summary>
        /// Refresh price change table
        /// </summary>
        /// <returns></returns>
        public static string RefreshPriceChangeTable()
        {
            return string.Format("2|GUEST|POST|REQ_PRICES_REFRESH_PRICE_CHANGE_TBL||||^");
        }

        /// <summary>
        /// Refresh pump status
        /// </summary>
        /// <returns></returns>
        public static string RefreshPumpStatus()
        {
            return string.Format("2|GUEST|POST|REQ_PUMP_STATUS_ID_000||||^");
        }

        #endregion

        #region Helper functions
        public static PumpState GetPumpStatus(string state)
        {
            PumpState ps = PumpState.Unknown;
            string stat = state.ToUpper();

            if (stat == "AUTHORIZED")
                ps = PumpState.Authorized;
            else if (stat == "CLOSED")
                ps = PumpState.Closed;
            else if (stat == "ERROR")
                ps = PumpState.Error;
            else if (stat == "OFFLINE")
                ps = PumpState.Offline;
            else if (stat == "CALLING")
                ps = PumpState.Calling;
            else if (stat == "STARTING")
                ps = PumpState.Starting;
            else if (stat == "FUELLING")
                ps = PumpState.Fuelling;
            else if (stat == "PAUSED")
                ps = PumpState.Suspended;
            else if (stat == "IDLE")
                ps = PumpState.Idle;
            else if (stat == "STOPPED")
                ps = PumpState.Stopped;
            return ps;
        }

        /// <summary>
        /// Fusion message router user password encryption
        /// </summary>
        /// <param name="inp"></param>
        /// <param name="inplen"></param>
        /// <param name="key"></param>
        /// <param name="keylen"></param>
        /// <returns></returns>
        public static char[] Crypt(char[] inp, int inplen, char[] key, int keylen)
        {
            //we will consider size of sbox 256 chars
            //(extra char are only to prevent any mishep just in case)
            char[] Sbox = new char[257];
            char[] Sbox2 = new char[257];
            int i, j, t, x;
            char temp, k = '\0';
            i = j = t = x = 0;
            temp = '\0';

            for (i = 0; i < 256; i++)
            {
                Sbox[i] = (char)0;
                Sbox2[i] = (char)0;
            }

            //initialize sbox i
            for (i = 0; i < 256; i++)
            {
                Sbox[i] = (char)i;
            }

            j = 0;
            //initialize the sbox2 with user key
            for (i = 0; i < 256; i++)
            {
                if (j == keylen)
                {
                    j = 0;
                }
                Sbox2[i] = key[j++];
            }

            j = 0; //Initialize j

            //scramble sbox1 with sbox2
            for (i = 0; i < 256; i++)
            {
                j = (j + Sbox[i] + Sbox2[i]) % 256;
                temp = Sbox[i];
                Sbox[i] = Sbox[j];
                Sbox[j] = temp;
            }
            i = j = 0;
            for (x = 0; x < inplen; x++)
            {
                //increment i
                i = (i + 1) % 256;
                //increment j
                j = (j + Sbox[i]) % 256;

                //Scramble SBox #1 further so encryption routine will
                //will repeat itself at great interval
                temp = Sbox[i];
                Sbox[i] = Sbox[j];
                Sbox[j] = temp;

                //Get ready to create pseudo random  char for encryption key
                t = (Sbox[i] + Sbox[j]) % 256;
                //get the random char
                k = Sbox[t];
                //xor with the data and done
                inp[x] = (char)(inp[x] ^ k);
            }
            return inp;
        }

        /// <summary>
        /// Binary to hex string conversion
        /// </summary>
        /// <param name="binStr"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static String BinToHexString(char[] binStr, int len)
        {
            char[] BINTOCHAR = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
            int i;
            String retStr = "";
            for (i = 0; i < len; i++)
            {
                retStr += "" + BINTOCHAR[(binStr[i] & 0xf0) >> 4] + "" + BINTOCHAR[binStr[i] & 0x0f];
            }
            return retStr;
        }

        /// <summary>
        /// Append space on right
        /// </summary>
        /// <param name="strIn"></param>
        /// <param name="numberofSpace"></param>
        /// <returns></returns>
        public static string AppendSpaceOnRight(string strIn, int numberofSpace)
        {
            int strInLength = strIn.Length;

            for (int i = 0; i < numberofSpace - strInLength; i++)
            {
                strIn += " ";
            }
            return strIn;
        }
        #endregion
    }


}