/*
 * menu.c
 *
 *  Created on: 1 февр. 2022 г.
 *      Author: radioman
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "menu.h"
#include "ssd1306.h"
#include "preferences.h"

static const char *menu_template[] = {\
"A, 0, 0, Dose rate",
"A, 0, 0, Total dose",
"A, 0, 0, Up time",
"A, 0, 0, Debug",
"D, 0, 0, Settings",
  "D, 0, 1, Sound",
    "P, 1, 2, Volume",
    "P, 2, 2, Tone",
    "P, 3, 2, Buttons",
    "B, 0, 2, Back",
  "D, 0, 1, Alarm",
    "D, 0, 2, Dose rate alarm",
      "R, 4, 3, OFF",
      "R, 4, 3, 0.5 uSv/h",
      "R, 4, 3, 1 uSv/h",
      "R, 4, 3, 10 uSv/h",
      "R, 4, 3, 100 uSv/h",
      "R, 4, 3, 1 mSv/h",
      "R, 4, 3, 10 mSv/h",
      "R, 4, 3, 100 mSv/h",
      "R, 4, 3, 1 Sv/h",
      "B, 0, 3, Back",
    "D, 0, 2, Total dose alarm",
      "R, 5, 3, OFF",
      "R, 5, 3, 1 uSv",
      "R, 5, 3, 10 uSv",
      "R, 5, 3, 100 uSv",
      "R, 5, 3, 1 mSv",
      "R, 5, 3, 10 uSv",
      "R, 5, 3, 100 uSv",
      "R, 5, 3, 1 Sv",
      "R, 5, 3, 10 Sv",
      "R, 5, 3, 100 Sv",
      "B, 0, 3, Back",
    "P, 6, 2, Sound type",
    "P, 7, 2, Volume",
    "B, 0, 2, Back",
  "D, 0, 1, Energy saving",
    "P, 8, 2, Brightness",
    "P, 9, 2, Disp.off min",
    "P, 10, 2, Shutdown min",
    "B, 0, 2, Back",
  "B, 0, 1, Back",
"A, 0, 0, Info" };

static menu_td menu_items[sizeof(menu_template) / sizeof(char*)];
static menu_td *menu = &menu_items[0];
static uint8_t scroll = 0;

extern uint8_t screen;

char * capstring(char *dest, const char *source)
{
  while(*source)
  {
    unsigned char c = *source++;
    // ASCII & CP1251 Cyrillic
    if((c >= 'a' && c <= 'z') || (c >= 0xe0 && c <= 0xff))
      c -= 32;
    *dest++ = c;
  }
  *dest = 0;
  return dest;
}

void MenuInit()
{
  uint8_t items_total = sizeof(menu_template) / sizeof(char*);
  char type;
  int max_level = 0;

  for(int i = 0; i < items_total; i++)
  {
    menu_items[i].id = i;
    sscanf(menu_template[i], "%c, %hhu, %hhu, %[^\n]",
        &type, &(menu_items[i].pref), &(menu_items[i].level), menu_items[i].title);
    menu_items[i].type = (entry_type)type;

    if(menu_items[i].level > max_level)
      max_level = menu_items[i].level;
  }

  /* Iterating through menu levels (complicated algorithm)*/
  for(int lvl = 0; lvl <= max_level; lvl++)
  {
    /* prev - previous entry ID on current level,
     * first - ID of first entry on current level */
    int prev = 0, first = -1;
    for(int i = 0; i < items_total; i++)
    {
      if(menu_items[i].level == lvl)
      {
        if(first < 0)
        {
          prev = first = i;
        }
        else
        {
          menu_items[prev].next = &menu_items[i];
          menu_items[i].prev = &menu_items[prev];
          prev = i;
        }

        /* At levels higher than 0 we assign parent and child pointers
         * All children have the same parent at one level
         * Parent always is the closest entry on lower level */
        if(lvl > 0)
        {
          menu_items[i].parent = &menu_items[first - 1];
          menu_items[first - 1].child = &menu_items[first];
        }
      }
      /* When we reaching entry that have lower level than our last entry
       * we need to close scroll loop by assigning 'next' pointer of last entry
       * to first entry on current level and reset 'first' variable
       * Also we need to do this if it is the last cycle of whole loop */
      if((first >= 0) && ((menu_items[i].level < menu_items[prev].level) || (i == (items_total - 1))))
      {
        menu_items[first].prev = &menu_items[prev];
        menu_items[prev].next = &menu_items[first];
        first = -1;
      }
    }
  }
}

void MenuScroll()
{
  scroll = 1;
  menu = menu->next;
}

void MenuEnter()
{
  switch(menu->type)
  {
    case ENTRY_DIR:
      menu = menu->child;
      break;
    case ENTRY_ACTION:
      screen = menu->id;
      //PrefSetValue(menu->pref, menu->id);
      //*(prefs[menu->pref].prefptr) = menu->id;
      break;
    case ENTRY_PREF:
      PrefIncValue(menu->pref);
      // *(prefs[menu->pref].prefptr) = (*(prefs[menu->pref].prefptr) +
      //    prefs[menu->pref].step) % (prefs[menu->pref].max_val + 1);
      break;
    case ENTRY_BACK:
      menu = menu->parent;
      break;
    case ENTRY_CHECK:
      PrefSetValue(menu->pref, PrefGetValue(menu->pref) ^ 1);
      //*(prefs[menu->pref].prefptr) ^= 1;
      break;
    case ENTRY_RADIO:
      PrefSetValue(menu->pref, menu->id - menu->parent->child->id);
      //*(prefs[menu->pref].prefptr) = menu->id - menu->parent->child->id;
      break;
  }
}

void PrintMenuHeader()
{
  char tempstr[30];
  if(menu->parent == NULL)
    strcpy(tempstr, "MAIN MENU");
  else
    capstring(tempstr, menu->parent->title);

  ssd1306_Line(0, 0, 127, 0, White);
  ssd1306_SetCursor(0, 1);
  ssd1306_WriteString("                   ", Font_7x10, Black);
  ssd1306_SetCursor(64 - ((strlen(tempstr) * 7) / 2), 1);
  ssd1306_WriteString(tempstr, Font_7x10, Black);
  ssd1306_Line(0, 10, 127, 10, Black);
}

char * FormatEntryText(menu_td *mn, char * buf)
{
  if(mn->type == ENTRY_PREF)
  {
    sprintf(buf, "%-12s -%.2d-", mn->title, PrefGetValue(mn->pref));
  }
  else if(mn->type == ENTRY_RADIO)
  {
    if(PrefGetValue(mn->pref) == (mn->id - mn->parent->child->id))
      sprintf(buf, "[%s]", mn->title);
    else
      sprintf(buf, "%s", mn->title);
  }
  else
  {
    strcpy(buf, mn->title);
  }

  return buf;
}

void MenuShow()
{
  static int x = 0, y = 0, an_steps = 0;
  char tempstr[30];

  ssd1306_Fill(Black);
/*
  ssd1306_SetCursor(1, 1);
  menu = &menu_items[1];
  sprintf(tempstr, "id: %s", menu->next->title);
  ssd1306_WriteString(tempstr, Font_7x10, White);
*/

  if(scroll)
  {
    y = 11;
    an_steps = 5;
    scroll = 0;
  }

  if(an_steps > 0)
  {
    an_steps--;
    y = (an_steps * 11) / 5;
  }

  ssd1306_SetCursor(x + 8, y + 1);
  ssd1306_WriteString(FormatEntryText(menu->prev, tempstr), Font_7x10, White);
  ssd1306_SetCursor(x + 8, y + 12);
  ssd1306_WriteString(FormatEntryText(menu, tempstr), Font_7x10, White);
  ssd1306_SetCursor(x + 8, y + 23);
  ssd1306_WriteString(FormatEntryText(menu->next, tempstr), Font_7x10, White);
  ssd1306_SetCursor(0, 12);
  if(menu->type == ENTRY_BACK)
    ssd1306_WriteChar('<', Font_7x10, White);
  else
    ssd1306_WriteChar('>', Font_7x10, White);
  PrintMenuHeader();

  ssd1306_UpdateScreen();
}
