// ---------------------------------------------------------------------------------------
        // setState: changes to the given retrieval state.  Handles all UI changes (enable/disable
        //      components, set text for messages, etc) for the new state
        // ---------------------------------------------------------------------------------------
        private void setState(RetrievalStates state, string msgData)
        {
            m_displayTimer.Stop();
            m_timeoutTimer.Stop();
            m_storageState = m_initialStorageState;
            m_retrievalState = state;
            Title = "Kiosk " + Constants.KIOSKID + " <" + state.ToString() + ">";
            disableLineDisplay();
            switch (state)
            {
                case RetrievalStates.Initial:
                    m_handicapped = false;
                    setButtonImage(BackgroundType.BlueButton, handicappedBtn);
                    setMsg("Swipe card to retrieve vehicle");
                    setInfo("To retrieve your car, please swipe the same card you used to store the car\n\nOr, you may create a monthly account by pushing the \"Create Monthly Account\" button");
                    //enableContextButton("Create Monthly Account");
                    disableOKCancel();
                    disableRateButtons();
                    disableHandicappedBtn();
                    m_accountState = MonthlyAccountStates.NotSelected;
                    enableContextButton("Create Monthly Account", 40);
                    m_createMonthlyOnStart = false;
                    //rateButtons[0].Visibility = Visibility.Hidden;
                    //debug
                    //if (SENDTOSIM)
                    //{
                        //sendMsg(KioskMsgType.wait_on_card_string, "", true);
                    //}
                    break;
                case RetrievalStates.SwipeNewMonthlyCC:
                    setMsg("Please swipe a credit card");
                    //TODO: create a better info message
                    setInfo("This credit card will be charged for\n" +
                             "the recurring monthly payments.\n" +
                             "If you already have a\n" +
                             "car stored in the garage,\n" +
                             "don't make a monthly account\n" +
                             "You will have the option to\n" +
                             "create an account as you\n" +
                             "retrieve your vehicle");

                    enableContextButton("Cancel");
                    disableOKCancel();
                    disableRateButtons();
                    disableHandicappedBtn();
                    m_accountState = MonthlyAccountStates.MCCError;
                    break;
                case RetrievalStates.WaitForDuration:
                    setMsg("Finding vehicle..");
                    setInfo("");
                    enableContextButton("Cancel");
                    disableOKCancel();
                    disableRateButtons();
                    break;
                case RetrievalStates.GetNewCC:
                    setMsg("Your card could not be charged.\nPlease swipe a new credit card for this\ntransaction.");
                    setInfo("");
                    enableContextButton("Cancel");
                    disableOKCancel();
                    disableRateButtons();
                    break;
                case RetrievalStates.DisplayDurationCC:
                    {
                        m_savedCard = msgData;
                        m_accountState = MonthlyAccountStates.NotSelected;
                        string[] data = msgData.Split(Constants.dataDelimiters);
                        TimeSpan duration;
                        if (data.Length < 3 || !TimeSpan.TryParse(data[0], out duration))
                        {
                            setState(RetrievalStates.DisplayError, "No valid duration found\nPlease see attendant");
                            break;
                        }
                        else
                        {

                            int minutes = duration.Minutes + Math.Sign(duration.Seconds);
                            int hours = duration.Hours;
                            int days = (int)duration.TotalDays;
                            if (minutes == 60)
                            {
                                ++hours;
                                minutes = 0;
                            }
                            if (hours == 24)
                            {
                                ++days;
                                hours = 0;
                            }

                            string durationString = "Your car has been parked for:\n";
                            // days
                            if (days == 1)
                            {
                                durationString += days.ToString() + " Day";
                            }
                            else if (days > 1)
                            {
                                durationString += days.ToString() + " Days";
                            }
                            // hours
                            if (hours == 1)
                            {
                                if (days >= 1)
                                {
                                    durationString += ", ";
                                }
                                durationString += hours.ToString() + " Hour";
                            }
                            else if (hours > 1 || days >= 1) // show 0 hours when showing days
                            {
                                if (days >= 1)
                                {
                                    durationString += ", ";
                                }
                                durationString += hours.ToString() + " Hours";
                            }
                            // minutes
                            if (minutes == 1)
                            {
                                if (hours > 0 || days > 0)
                                {
                                    durationString += ", ";
                                }
                                durationString += minutes.ToString() + " Minute";
                            }
                            else if (minutes > 1 || hours >= 1)
                            {
                                if (hours > 0 || days > 0)
                                {
                                    durationString += ", ";
                                }
                                durationString += minutes.ToString() + " Minutes";
                            }

                            string cost = "Total: $" + data[1];

                            setMsg(durationString + "\n\n" + cost + "\n\nThis will be charged to your\ncard ending in: " + data[2]);
                            setInfo("Press OK to charge your card and retrieve your car\n\nNo charges will be made until you press OK");
                            enableOkCancel();
                            //max number of accounts already reached
                            if (data[3].ToLower().Contains("t") || !monthlyCreEnabled)
                            {
                                disableContextButton();
                            }
                            else
                            {
                                enableContextButton("Create Monthly Account", 40);
                            }
                            disableRateButtons();
                            enableHandicappedBtn(m_handicappedText);
                            //debug
                            //if (SENDTOSIM)
                            //{
                                //sendMsg(KioskMsgType.wait_for_confirm, "", true);
                                Title = "Kiosk " + Constants.KIOSKID + " <" + state.ToString() + "> <wait for confirm sent>";
                            //}
                        }
                        break;
                    }
                case RetrievalStates.DisplayDurationDL:
                    {
                        string[] data = msgData.Split(Constants.dataDelimiters);
                        TimeSpan duration;
                        if (data.Length < 1 || !TimeSpan.TryParse(data[0], out duration))
                        {
                            // error
                        }
                        else
                        {
                            string days = ((int)duration.TotalDays).ToString();
                            string hours = duration.Hours.ToString();
                            string minutes = (duration.Minutes + Math.Sign(duration.Seconds)).ToString(); //round any seconds up to the next minute
                            string durationString = "Your car has been parked for:\n" + days + " Days\n" + hours + " Hours\n" + minutes + " Minutes";

                            setMsg(durationString);
                            setInfo("Press OK to retrieve your car");
                            disableContextButton();
                            enableOkCancel();
                            disableRateButtons();
                            if (data.Length > 1 && data[1].ToLower().Equals("true"))
                            {
                                handicappedBtn.Content = TK_Handi_On;
                                setButtonImage(BackgroundType.GreenButton, handicappedBtn);
                            }
                            enableHandicappedBtn(m_handicappedText);
                        }
                    }
                    break;
                case RetrievalStates.SwipeNewMonthlyDL:
                    setMsg("Please swipe your California driver's\n license");
                    setInfo("Your monthly account will be associated with this card.");
                    enableContextButton("Cancel");
                    disableOKCancel();
                    disableRateButtons();
                    disableHandicappedBtn();
                    m_accountState = MonthlyAccountStates.SwipeDl;
                    m_monthlyAccountCre = true;
                    break;
                case RetrievalStates.WaitForDlAuth:
                    setMsg("Verifying license..");
                    setInfo("");
                    disableContextButton();
                    disableOKCancel();
                    disableRateButtons();
                    disableHandicappedBtn();
                    break;
                case RetrievalStates.CreateAccountInit:
                    m_accountState = MonthlyAccountStates.CustomizeAccount;
                    setMsg("Configure Your Account: ");
                    disableContextButton();
                    disableOKCancel();
                    enableAllRateBtns();
                    //TODO: Display rates.  Create GUI.
                    setInfo("1) Choose your account duration." +
                            "\n2) Select a credit card. This" +
                            "\n    defaults to the card with" +
                            "\n    which you originally stored" +
                            "\n    your vehicle, if you didn't." +
                            "\n    start the account creation" +
                            "\n    from the initial retrieve" +
                            "\n    kiosk screen. " +
                            "\n3) Select whether or not you" +
                            "\n    want " + TK_Handi_Dsc + ".");
                    enableContextButton("Input Credit Card");
                    enableOkCancel();
                    enableHandicappedBtn(m_handicappedText);
                    break;
                case RetrievalStates.AlternateCardForMonthly:
                    setMsg("Please swipe a credit card");
                    //TODO: create a better info message
                    setInfo("This credit card will be charged for\nthe recurring monthly payments.");
                    enableContextButton("Cancel");
                    disableOKCancel();
                    disableRateButtons();
                    disableHandicappedBtn();
                    break;
                case RetrievalStates.VerifyAlternateMonthlyCC:
                    setMsg("Verifying new credit card..");
                    disableContextButton();
                    disableOKCancel();
                    disableRateButtons();
                    disableHandicappedBtn();
                    break;
                case RetrievalStates.WaitForAuth:
                    setMsg("Authorizing card\nplease wait..");
                    setInfo("");
                    disableContextButton();
                    disableOKCancel();
                    disableRateButtons();
                    disableHandicappedBtn();
                    break;
                case RetrievalStates.AccountVerify:
                    setMsg("Verifying account details");
                    setInfo("");
                    disableContextButton();
                    disableOKCancel();
                    disableRateButtons();
                    disableHandicappedBtn();
                    break;
                case RetrievalStates.ConfirmMonthlyCreation:
                    //firstname, last4digits, duration, monthlyrate, total cost, disabled parking T or F
                    string[] accountInfo = msgData.Split(Constants.dataDelimiters, StringSplitOptions.RemoveEmptyEntries);
                    string verifyMsg = "Create Account?";
                    verifyMsg += "\n\nName: " + accountInfo[0];
                    verifyMsg += "\nCredit Card last 4: " + accountInfo[1];
                    verifyMsg += "\nAccount Duration: " + accountInfo[2] + " months";
                    verifyMsg += "\nMonthly Rate: $" + accountInfo[3];
                    verifyMsg += "\n" + TK_Handi_Dsc + ": ";

                    if (accountInfo.Length >= 5 && accountInfo[5].ToLower().Contains("t"))
                    {
                        verifyMsg += "Yes";
                    }
                    else
                    {
                        verifyMsg += "No";
                    }

                    setMsg(verifyMsg);
                    //TODO: Display data that was sent in the msgData string
                    setInfo("");
                    disableRateButtons();
                    enableContextButton("Edit Account");
                    enableOkCancel();
                    disableHandicappedBtn();
                    break;
                case RetrievalStates.CreateAccountAndRetrieveCar:
                    disableContextButton();
                    disableOKCancel();
                    disableHandicappedBtn();
                    string msg = "Creating Account";
                    bool retrieve = true;
                    if (retrieve)
                    {
                        msg += " and Retrieving Vehicle";
                        msg += "\nWatch the overhead display to see where\nyour car will be delivered";
                    }
                    setInfo("");
                    m_displayTimer.Start();
                    setMsg(msg);
                    break;
                case RetrievalStates.ProcessingDL:
                    setMsg("Processing,\nplease wait..");
                    setInfo("");
                    disableContextButton();
                    disableOKCancel();
                    break;
                case RetrievalStates.Processing:
                    disableContextButton();
                    disableOKCancel();
                    disableRateButtons();
                    disableHandicappedBtn();
                    setMsg("Processing..");
                    break;
                case RetrievalStates.OutboundAccepted:
                    string message = "";
                    setInfo("");
                    if (m_accountState == MonthlyAccountStates.AccountVerified)
                    {
                        message = "Account created.";

                    }

                    if (!m_createMonthlyOnStart)
                    {
                        if (message.Length > 0)
                        {
                            //account created
                            message += "\n";
                        }
                        message += "Retrieval request created successfully";
                        if (m_accountState != MonthlyAccountStates.AccountVerified && m_sortser.Length > 0)
                        {
                            message += "\n\nWould you like a receipt of this\ntransaction?";
                            enableOkCancel("Yes", "No");
                        }
                        else
                        {
                            disableOKCancel();
                        }
                        setInfo("Watch the overhead display to see which bay your car will be retrieved to");
                    }
                    setMsg(message);

                    //setMsg("Watch the overhead display to see the bay to which your car will be retrieved");
                    m_displayTimer.Interval = new TimeSpan(0, 0, 0, 25, 0); // Tom says 25 seconds for this
                    m_displayTimer.Start();
                    disableContextButton();
                    disableRateButtons();

                    break;
                case RetrievalStates.DisplayError:
                    setMsg(msgData, true);
                    setInfo("");
                    disableContextButton();
                    disableOKCancel();
                    disableHandicappedBtn();
                    disableRateButtons();
                    //debug
                    //if (SENDTOSIM)
                    //{
                        //sendMsg(KioskMsgType.ERROR_sim, "", true);
                    //}
                    m_displayTimer.Start();
                    break;
            }
        }
        private void DoUILayoutCalculation()
        {
            m_createMonthlyOnStart = false;
            chosenMonthlyRateIndex = -1;
            m_handicapped = false;
            m_handicappedText = TK_Handi_Off;
            m_sortser = "";

            switch (m_rates.Count)
            {
                //will have to add 12 to the margin numbers
                case 1:
                    offset = 396;
                    break;
                case 2:
                    offset = 257;
                    break;
                case 3:
                    offset = 138;
                    break;
                case 4:
                    offset = 12;
                    break;
                default:
                    break;
            }

            rateButtons.Add(rateBtn1);
            rateButtons.Add(rateBtn2);
            rateButtons.Add(rateBtn3);
            rateButtons.Add(rateBtn4);

            m_rateBorders.Add(borderRateBtn1);
            m_rateBorders.Add(borderRateBtn2);
            m_rateBorders.Add(borderRateBtn3);
            m_rateBorders.Add(borderRateBtn4);

            foreach (Button b in rateButtons)
            {
                b.FontSize = 36.0;
                b.Visibility = Visibility.Hidden;
            }

            handicappedBtn.Content = m_handicappedText;
            handicappedBtn.Visibility = Visibility.Hidden;
            handicappedBtn.FontSize = 35.0;
            setButtonImage(BackgroundType.BlueButton, rateBtn2);

            m_timer1 = new DispatcherTimer();
            m_timer1.Tick += new EventHandler(timer1_Tick);
            m_timer1.Interval = new TimeSpan(0, 0, 0, 0, 200); // 200 ms

            m_cardSwipeTimer = new DispatcherTimer();
            m_cardSwipeTimer.Tick += new EventHandler(cardSwipeTimer_Tick);
            m_cardSwipeTimer.Interval = new TimeSpan(0, 0, 0, 0, 200); // 200 ms

            m_displayTimer = new DispatcherTimer();
            m_displayTimer.Tick += new EventHandler(displayTimer_Tick);
            m_displayTimerDefaultInterval = new TimeSpan(0, 0, 0, 10, 0); // 10 s
            m_displayTimer.Interval = m_displayTimerDefaultInterval;

            m_timeoutTimer = new DispatcherTimer();
            m_timeoutTimer.Tick += new EventHandler(timeoutTimer_Tick);
            m_timeoutTimer.Interval = new TimeSpan(0, 0, 2, 0, 0); // 120 s (2 minutes)

            m_storageState = m_initialStorageState;
            m_retrievalState = m_initialRetrievalState;
            m_accountState = MonthlyAccountStates.NotSelected;
            vehicleRetrieved = false;

            m_lastKillBitCheck = DateTime.Now;
            m_killBitInterval = new TimeSpan(0, 0, 0, 2, 0); // 2 s

            switch (Constants.KIOSKID[0])
            {
                case '0':
                    m_kioskMode = KioskMode.Storage;
                    break;
                case '9':
                    m_kioskMode = KioskMode.Retrieval;
                    break;
                default:
                    throw new InvalidOperationException("Invalid kiosk id from command line: " + Constants.KIOSKID);
            }

            //initComm();
        }
        // ---------------------------------------------------------------------------------------
        // setState: changes to the given storage state.  Handles all UI changes (enable/disable
        //      components, set text for messages, etc) for the new state
        // ---------------------------------------------------------------------------------------
        private void setState(StorageStates state, string msgData)
        {
            m_timeoutTimer.Stop();
            m_displayTimer.Stop();
            m_retrievalState = m_initialRetrievalState;
            m_storageState = state;
            setBackground(BackgroundType.Active);

            Title = "Kiosk " + Constants.KIOSKID + " <" + state.ToString() + ">";

            switch (state)
            {
                case StorageStates.DisplayError:
                    setMsg(msgData, true);
                    // leave info as is
                    disableContextButton();
                    disableOKCancel();
                    m_displayTimer.Start();
                    //debug
                    //if (SENDTOSIM)
                    //{
                        //sendMsg(KioskMsgType.ERROR_sim, "", true);
                    //}
                    break;
                case StorageStates.InboundAccepted:
                    setMsg("Your vehicle will now be stored\nThank you");
                    // leave info as is
                    disableContextButton();
                    disableOKCancel();
                    m_displayTimer.Start();
                    break;
                case StorageStates.WaitForAuth:
                    {
                        setMsg("Authorizing Card\nPlease wait..");
                        // keep info as is
                        enableContextButton("Cancel");
                        disableOKCancel();
                        m_timeoutTimer.Start();
                        break;
                    }
                case StorageStates.WaitForCard:
                    setMsg("Please swipe card to start");
                    setInfo("Monthly Users:\n\u2022Swipe your driver's license,\nUCLA card, or UCLA RFID\n\nHourly Users:\n\u2022Swipe your credit card\n\u2022The card you swipe will be required to retrieve your vehicle\n\u2022Your card will not be charged until you retrieve your vehicle");
                    disableContextButton();
                    disableOKCancel();
                    //debug
                    //if (SENDTOSIM)
                    //{
                        //sendMsg(KioskMsgType.wait_on_card_string, "", true);
                    //}
                    break;
                case StorageStates.WaitForConfirm:
                    {
                        string[] data = msgData.Split(Constants.dataDelimiters);
                        string infoString = "";
                        if (data.Length < 2 || data[0].Length != 4)
                        {
                            // invalid data, skip info msg creation
                        }
                        else
                        {
                            infoString = "\nLast 4 of Card#: " + data[0] + "\nUser Type: " + data[1]; // first \n is for extra newline in addtion to the one added by appendInfo
                        }

                        setMsg("Ready to store vehicle\n\nBy pressing START you confirm that\neveryone is out of the vehicle", false);
                        //debug
                        //if (SENDTOSIM)
                        //{
                            //sendMsg(KioskMsgType.wait_for_confirm, "", true);
                        //}
                        appendInfo(infoString);
                        disableContextButton();
                        enableOkCancel("START");
                        break;
                    }
                case StorageStates.Processing:
                    {
                        setMsg("Processing");
                        setInfo("");
                        disableContextButton();
                        disableOKCancel();
                        m_timeoutTimer.Start();
                    }
                    break;
                case StorageStates.WaitForLocation:
                    {
                        string infoString = "";
                        string[] data = msgData.Split(Constants.dataDelimiters);
                        if (data.Length < 4)
                        {
                            // invalid data, skip info msg creation
                        }
                        else
                        {
                            int geocl;
                            if (!(Int32.TryParse(data[3], out geocl) && geocl >= 0 && geocl < Constants.geocl2str.Length))
                            {
                                geocl = 0; // "UNKNOWN"
                            }
                            for (int i = 0; i < 3; i++) // first 3 are height, length, width
                            {
                                data[i] = "000" + data[i];
                                data[i] = data[i].Substring(0, data[i].Length - 3) + "." + data[i].Substring(data[i].Length - 3, 3);
                                data[i].TrimStart(Constants.zero);
                                if (data[i][0] == '.')
                                {
                                    data[i] = "0" + data[i];
                                }
                            }
                            infoString = "Your vehicle:\nHeight: " + formatSize(data[0]) + "\nLength: "
                                + formatSize(data[1]) + "\nWidth: " + formatSize(data[2]) + "\nType: " + Constants.geocl2str[geocl];

                        }
                        setMsg("Finding storage location\nfor your vehicle\nplease wait..", false);
                        setInfo(infoString);
                        enableContextButton("Cancel");
                        disableOKCancel();
                        m_timeoutTimer.Start();
                        break;
                    }
                case StorageStates.WaitForReady:
                    setMsg("Kiosk Disabled");
                    setInfo("");
                    disableContextButton();
                    disableOKCancel();
                    setBackground(BackgroundType.Inactive);
                    break;
                case StorageStates.WaitForSize:
                    setMsg("Sizing vehicle\nPlease wait..");
                    setInfo("");
                    enableContextButton("Cancel");
                    disableOKCancel();
                    m_timeoutTimer.Start();
                    break;
                default:
                    throw new InvalidOperationException();

            }
        }