#include "lgi/common/Lgi.h"
#include "mc4.h"
#include "lgi/common/TextLabel.h"
#include "lgi/common/Button.h"
#include "lgi/common/LgiRes.h"
#include "resdefs.h"

const char *ToString(HwButton b)
{
	switch (b)
	{
		#define _(n) case BtnType##n: return #n;
		_(None)
		_(Tuner)
		_(Tempo)
		_(IA)
		_(Preset)
		_(BankUp)
		_(BankDown)
		_(ModeSwitch)
		_(Bank)
		_(DelayDivision)
		#undef _
		default:
			LAssert(!"Impl me.");
			break;
	}
	return "#err";
}

class ButtonSetupDlg;
class ButtonTypeDlg : public Mc4Dialog
{
	ButtonSetupDlg *Parent;

public:
	int x, y;

	ButtonTypeDlg(Mc4Ui *ui, ButtonSetupDlg *parent, int X, int Y) : Mc4Dialog(ui)
	{
		Parent = parent;
		x = X;
		y = Y;
		Load();
	}

	bool Load()
	{
		if (!Ui->LoadResource(IDD_BUTTON_TYPE))
			return false;

		return true;
	}

	int OnNotify(LViewI *Ctrl, LNotification n);
};

class ButtonSetupDlg : public Mc4Dialog
{
	LString PaneFmt;
	int CurPane;

public:
	ButtonSetupDlg(Mc4Ui *ui) : Mc4Dialog(ui)
	{
		CurPane = -1;
		Load();
	}

	bool SetButton(HwButton type, ButtonTypeDlg *dlg)
	{
		{
			auto Sh = Shared->Lock(_FL);
			if (!Sh)
				return false;

			if (dlg->x >= 0 && dlg->x < BUTTONS_X &&
				dlg->y >= 0 && dlg->y < BUTTONS_Y &&
				CurPane >= 0 && CurPane < MAX_BUTTON_PANES)
			{
				Sh->Global.BtnConfig[CurPane][dlg->x][dlg->y] = type;
				Sh->Global.ReindexBtns();
			}
		}

		delete dlg;
		return Load();
	}

	bool Update()
	{
		LTableLayout *t;
		if (!Ui->GetViewById(IDC_BTN_SETUP, t))
			return false;

		auto Sh = Shared->Lock(_FL);
		if (!Sh)
			return false;

		if (CurPane < 0)
			CurPane = Sh->Global.CurrentBtnPane;

		LString s;
		s.Printf(PaneFmt, CurPane+1, MAX_BUTTON_PANES);
		Ui->SetCtrlName(IDC_PANE, s);

		int id = BTN_DEF_BASE;
		for (int y=0; y<BUTTONS_Y; y++)
		{
			for (int x=0; x<BUTTONS_X; x++)
			{
				auto type = Sh->Global.BtnConfig[CurPane][x][y];
				auto n = type.b == BtnTypeModeSwitch ? "Mode\nSwitch" : ToString(type.b);
				LString name;
				if (type.b == BtnTypePreset ||
					type.b == BtnTypeIA ||
					type.b == BtnTypeBank)
					name.Printf("%s%i", n, type.i + 1);
				else if (type.b == BtnTypeDelayDivision &&
						type.i < CountOf(Mc4DelayTempoNames))
					name = Mc4DelayTempoNames[type.i];
				else name = n;

				auto c = t->GetCell(x, y);
				auto ch = c->GetChildren();
				LButton *b;
				if (ch.Length())
				{
					// Has existing button... reuse
					b = dynamic_cast<LButton*>(ch[0]);
					if (!b)
						return false;
					b->SetId(id++);
				}
				else
				{
					// First update: create new button
					b = new LButton(id++);
					c->Add(b);
				}
				b->Name(name);
				b->CssClasses()->New() = "BtnCfg";
				LResources::StyleElement(b);
				b->OnStyleChange();
			}
		}

		return true;
	}

	bool Load()
	{
		if (!Ui->LoadResource(Resource = IDD_SETUP_BTNS))
			return false;

		PaneFmt = Ui->GetCtrlName(IDC_PANE);
		return Update();
	}

	int OnNotify(LViewI *Ctrl, LNotification n)
	{
		switch (Ctrl->GetId())
		{
			case IDC_PREV:
			{
				if (CurPane > 0)
				{
					CurPane--;
					Update();
				}
				return true;
			}
			case IDC_NEXT:
			{
				if (CurPane < MAX_BUTTON_PANES - 1)
				{
					CurPane++;
					Update();
				}
				return true;
			}
			case IDC_DEFAULTS:
			{
				auto Sh = Shared->Lock(_FL);
				if (!Sh)
					return false;

				if (CurPane < 0)
					CurPane = Sh->Global.CurrentBtnPane;

				switch (CurPane)
				{
					case 0:
					{
						auto &i = Sh->Global.BtnConfig[CurPane];
						i[0][0] = BtnTypeTuner;
						i[0][1] = BtnTypeTempo;
						i[BUTTONS_X-1][0] = BtnTypeModeSwitch;
						for (int x=1; x<BUTTONS_X-1; x++)
							i[x][0] = BtnTypePreset;
						for (int x=1; x<BUTTONS_X; x++)
							i[x][1] = BtnTypeIA;
						break;
					}
					case 1:
					{
						auto &i = Sh->Global.BtnConfig[CurPane];
						for (int y=0; y<BUTTONS_Y; y++)
						{
							for (int x=0; x<BUTTONS_X; x++)
								if (x == BUTTONS_X-1 && y == 0)
									i[x][y] = BtnTypeModeSwitch;
								else
									i[x][y] = BtnTypeBank;
						}
						break;
					}
					case 2:
					{
						auto &i = Sh->Global.BtnConfig[CurPane];
						for (int y=0; y<BUTTONS_Y; y++)
						{
							for (int x=0; x<BUTTONS_X; x++)
								if (x == BUTTONS_X-1 && y == 0)
									i[x][y] = BtnTypeModeSwitch;
								else if (x < CountOf(Mc4DelayTempos) && y == 0)
									i[x][y] = BtnTypeDelayDivision;
								else
									i[x][y] = BtnTypeNone;
						}
						break;
					}
					default:
						LAssert(!"Impl me.");
						break;
				}
				
				Sh->Global.ReindexBtns();
				return Update();
			}
			default:
			{
				int Id = Ctrl->GetId();
				int Btns = BUTTONS_X * BUTTONS_Y;
				if (Id >= BTN_DEF_BASE && Id < BTN_DEF_BASE + Btns)
				{
					int Idx = Id - BTN_DEF_BASE;
					int x = Idx % BUTTONS_X;
					int y = Idx / BUTTONS_X;
					new ButtonTypeDlg(Ui, this, x, y);
					return true;
				}
				break;
			}
		}

		return Mc4Dialog::OnNotify(Ctrl, n);
	}
};

int ButtonTypeDlg::OnNotify(LViewI *Ctrl, LNotification n)
{
	switch (Ctrl->GetId())
	{
		case IDC_NONE:
			return Parent->SetButton(BtnTypeNone, this);
		case IDC_TUNER:
			return Parent->SetButton(BtnTypeTuner, this);
		case IDC_TEMPO:
			return Parent->SetButton(BtnTypeTempo, this);
		case IDC_IA:
			return Parent->SetButton(BtnTypeIA, this);
		case IDC_PRESET:
			return Parent->SetButton(BtnTypePreset, this);
		case IDC_BANKUP:
			return Parent->SetButton(BtnTypeBankUp, this);
		case IDC_BANKDOWN:
			return Parent->SetButton(BtnTypeBankDown, this);
		case IDC_MODE_SWITCH:
			return Parent->SetButton(BtnTypeModeSwitch, this);
		case IDC_BANK:
			return Parent->SetButton(BtnTypeBank, this);
		case IDC_DELAY_DIV:
			return Parent->SetButton(BtnTypeDelayDivision, this);			
	}

	return Mc4Dialog::OnNotify(Ctrl, n);
}

class PedalSetupDlg : public Mc4Dialog
{
public:
	PedalSetupDlg(Mc4Ui *ui) : Mc4Dialog(ui)
	{
		Load();
	}

	bool Load()
	{
		return Ui->LoadResource(Resource = IDD_SETUP_PEDALS);
	}
};

class DisplaySetupDlg : public Mc4Dialog
{
public:
	DisplaySetupDlg(Mc4Ui *ui) : Mc4Dialog(ui)
	{
		Load();
	}

	bool Load()
	{
		return Ui->LoadResource(Resource = IDD_SETUP_DISPLAYS);
	}
};

class AboutDlg : public Mc4Dialog
{
public:
	AboutDlg(Mc4Ui *ui) : Mc4Dialog(ui)
	{
		Load();
	}

	bool Load()
	{
		if (!Ui->LoadResource(Resource = IDD_ABOUT))
			return false;
			
		LString s;
		LString sVer;
		LArray<int> Ver;
		LGetOs(&Ver);
		for (unsigned i=0; i<Ver.Length(); i++)
		{
			LString v;
			v.Printf("%s%i", i?".":"", Ver[i]);
			sVer += v;
		}
		const char *OsName = LGetOsName();			

		s.Printf("Memecode Controller: v%s\n"
				" \n"
				"OS: %s v%s\n",
				APP_VER,
				OsName, sVer.Get());

		Ui->SetCtrlName(IDC_ABOUT_TXT, s);
		return true;
	}
};

SetupDlg::SetupDlg(Mc4Ui *ui) : Mc4Dialog(ui)
{
	Load();
}

SetupDlg::~SetupDlg()
{
	printf("~SetupDlg() PresetDirty=%i GlobalDirty=%i\n", PresetDirty, GlobalDirty);
	if (PresetDirty)
		Ui->SerializePreset(true);
	if (GlobalDirty)
	{
		Ui->SerializeGlobal(true);
		Ui->UpdateButtonLabels();
	}
}

void SetupDlg::SetIaGroup(int Ia, int Grp)
{
	auto Sh = Shared->Lock(_FL);
	if (Sh)
	{
		auto Press = Sh->Preset.GetTypePress();
		if (Press.IdxCheck(Ia))
		{
			auto i = Press[Ia];
			if (i->Group != Grp)
			{
				i->Group = Grp;
				PresetDirty = true;
			}
		}
	}
}

const char *BtnColours[] = {"#444", "#f4f4f4"};

bool SetupDlg::Load()
{
	PresetDirty = false;
	GlobalDirty = false;
	if (!Ui->LoadResource(Resource = IDD_SETUP))
		return false;

	LTableLayout *t;
	if (Ui->GetViewById(IDC_PRESET_GROUPS, t))
	{
		int id = GROUP_BASE;
		LTextLabel *txt;

		LArray<int> IaGrps;
		{
			auto Sh = Shared->Lock(_FL);
			if (Sh)
			{
				auto IAs = Sh->Preset.GetTypePress();
				for (unsigned i=0; i<IAs.Length(); i++)
					IaGrps[i] = IAs[i]->Group;
			}
			while (IaGrps.Length() < IA_BTNS)
				IaGrps.Add(-1);
		}

		for (int x=0; x<IA_BTNS; x++)
		{
			auto c = t->GetCell(1 + x, 0);
			LString s;
			s.Printf("IA%i", x+1);
			c->Add(txt = new LTextLabel(-1, 0, 0, -1, -1, s));
			c->TextAlign(LCss::AlignCenter);
			txt->GetCss(true)->FontSize("14pt");
			txt->OnStyleChange();
		}

		for (int y=0; y<IA_BTNS; y++)
		{
			auto c = t->GetCell(0, 1+y);
			LString s;
			s.Printf("Grp%i", y+1);
			c->Add(txt = new LTextLabel(-1, 0, 0, -1, -1, s));
			c->VerticalAlign(LCss::VerticalMiddle);
			txt->GetCss(true)->FontSize("14pt");
			txt->OnStyleChange();

			for (int x=0; x<IA_BTNS; x++)
			{
				auto c = t->GetCell(1+x, 1+y);
				LButton *b = new LButton(id++);
				b->SetIsToggle(true);
				
				if (IaGrps[x] >= 0)
					b->Value(IaGrps[x] == y);
				else
					b->Value(x == y);

				auto css = b->GetCss(true);
				css->BackgroundColor(BtnColours[b->Value() != 0]);
				css->Height("46px");
				css->Width("54px");
				c->Add(b);
			}
		}
		
		t->InvalidateLayout();
		t->SendNotify(LNotifyTableLayoutRefresh);
	}

	return true;
}

int SetupDlg::OnNotify(LViewI *Ctrl, LNotification n)
{
	switch (Ctrl->GetId())
	{
		// Setup page
		case IDC_SETUP_BUTTONS:
			new ButtonSetupDlg(Ui);
			return true;
		case IDC_SETUP_PEDALS:
			new PedalSetupDlg(Ui);
			return true;
		case IDC_SETUP_DISPLAYS:
			new DisplaySetupDlg(Ui);
			return true;
		case IDC_ABOUT:
			new AboutDlg(Ui);
			return true;
		case IDC_EXIT:
			LCloseApp();
			return true;
		case IDC_SHUTDOWN:
			if (LgiMsg(Ui, "Do you really want to shutdown?", "MC4", MB_YESNO) == IDYES)
			{
				#ifdef LINUX
				LCloseApp();
				int i = system("sudo halt &");
				#endif
			}
			else
			{
				LgiTrace("Got no...\n");
			}
			return true;
		/*
		case IDC_SETUP_TABLE:
			if (Flags == LNotifyTableLayoutChanged)
			{
				int ids[] = { IDC_BACK, IDC_SETUP_BUTTONS, IDC_SETUP_PEDALS, IDC_SETUP_DISPLAYS, IDC_ABOUT, IDC_EXIT, IDC_SHUTDOWN };
				SameWidth(CountOf(ids), ids);
				return true;
			}
			break;
		*/
		case IDC_RESET:
		{
			for (int y=0; y<IA_BTNS; y++)
			{
				for (int x=0; x<IA_BTNS; x++)
				{
					int Idx = y * IA_BTNS + x;
					int Id = GROUP_BASE + Idx;
					LButton *b;
					if (Ui->GetViewById(Id, b))
					{
						b->Value(x == y);
						b->GetCss(true)->BackgroundColor(BtnColours[b->Value() != 0]);
					}
				}

				SetIaGroup(y, y);
			}
			break;
		}
		default:
		{
			auto Id = Ctrl->GetId();
			int Btns = IA_BTNS * IA_BTNS;
			if (Id >= GROUP_BASE && Id < GROUP_BASE + Btns)
			{
				int Idx = Id - GROUP_BASE;
				int Grp = Idx / IA_BTNS;
				int Ia = Idx % IA_BTNS;

				// Check only one per col is selected
				for (int y=0; y<IA_BTNS; y++)
				{
					LButton *b;
					if (Ui->GetViewById(GROUP_BASE + (y * IA_BTNS) + Ia, b))
					{
						if (y != Grp)
							b->Value(false);
						b->GetCss(true)->BackgroundColor(BtnColours[b->Value() != 0]);
					}
				}

				// Update the preset
				SetIaGroup(Ia, Grp);
				return true;
			}
			break;
		}
	}

	return Mc4Dialog::OnNotify(Ctrl, n);
}

