//
// Created by robtor on 05.01.23.
//

#include "Menu_Controller.h"

namespace floatpump::menu {

    void Menu_Controller::execute() {
        displayMenu(m_menu);
    }

    void Menu_Controller::pushEvent(Menu_Controller::Event ev) {
        switch (ev) {
            case Increase:
                increase(m_menu);
                break;
            case Decrease:
                decrease(m_menu);
                break;
            case Push:
                keypress(m_menu);
                break;
        }
    }

    void Menu_Controller::displayMenu(Menu *m) {
        int page = m_current_index / 4;         //Currently displayed page
        int pageindex = m_current_index % 4;    //Current line on page

        for (int i = 0; i < 4; i++) {
            m_driver.LCDSetCursor(0, i);

            //Set arrow marker for currently selected line
            if (pageindex == i) {
                m_driver.LCDSendChar(LCD_I2C_Driver::SpecialChars::RightArrow);
            } else {
                m_driver.LCDSendCString((char *) " ");
            }

            m_driver.LCDSetCursor(1, i);

            //Map screen line numbers to index
            int entry_index = (page * 4) + i;

            //Retreive menu contents
            auto menutexts = m->getDisplayList();

            if (entry_index < m->getAllEntriesNum()) {
                std::string dspstring = menutexts[entry_index];

                if (dspstring.length() > 19) {
                    dspstring = "-- ERR --";
                } else {
                    dspstring.append((19 - dspstring.length()), ' ');
                }

                m_driver.LCDSendCString(const_cast<char *>(dspstring.c_str()));
            } else {
                //Clear rest of screen if not fully containing a menu
                m_driver.LCDSendCString((char *) "                   ");
            }
        }
    }

    void Menu_Controller::keypress(Menu *m) {
        //Enter submenu if entry is submenu
        if (m->getSubmenu(m_current_index) != nullptr) {
            //Replace containing menu with submenu
            m_menu = m->getSubmenu(m_current_index);
            m_current_index = 0;
            //Forward press action if entry is entry
        } else if (m->getEntry(m_current_index) != nullptr) {
            m->getEntry(m_current_index)->u_press();
            //If we are on the Go-Back-Entry and have a parent: replace menu with parent menu
        } else if (m_menu->getParent() != nullptr) {
            m_menu = m_menu->getParent();
            m_current_index = 0;
        }
    }

    void Menu_Controller::increase(Menu *m) {
        if (m_current_index < m->getAllEntriesNum()) {
            if (m->getEntry(m_current_index) != nullptr) {
                //Forward increase action to entry if we have an entered entry
                if (m->getEntry(m_current_index)->is_entered()) {
                    m->getEntry(m_current_index)->u_increase();
                } else if (m_current_index < m->getAllEntriesNum() - 1) {
                    m_current_index++;
                }
            } else if (m_current_index < m->getAllEntriesNum() - 1) {
                m_current_index++;
            }
        } else if (m_current_index < m->getAllEntriesNum() - 1) {
            m_current_index++;
        }
    }

    void Menu_Controller::decrease(Menu *m) {
        if (m_current_index > 0) {
            if (m->getEntry(m_current_index) != nullptr) {
                //Forward decrease action to entry if we have an entered entry
                if (m->getEntry(m_current_index)->is_entered()) {
                    m->getEntry(m_current_index)->u_decrease();
                } else {
                    m_current_index--;
                }
            } else {
                m_current_index--;
            }
        }
    }
} // menu