/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

/*
 * This code is based on the original source code of Lord Avalot d'Argent version 1.3.
 * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
 */

 /* DROPDOWN	A customised version of Oopmenu (qv). */

#include "avalanche/avalanche.h"

#include "avalanche/dropdown2.h"

#include "avalanche/lucerna2.h"
#include "avalanche/gyro2.h"
#include "avalanche/acci2.h"
#include "avalanche/trip6.h"
#include "avalanche/enid2.h"
#include "avalanche/basher2.h"

#include "common/textconsole.h"

namespace Avalanche {

headtype *headtype::init(char trig, char alttrig, Common::String name, byte p, func dw, func dc, Dropdown *dr) {
	_dr = dr;

	trigger = trig;
	alttrigger = alttrig;
	title = name;
	position = p;
	xpos = (position - 1) * _dr->spacing + _dr->indent;
	xright = position * _dr->spacing + _dr->indent;
	do_setup = dw;
	do_choose = dc;

	return this;
}

void headtype::display() {
	_dr->_vm->_gyro->off(); /*MT*/
	_dr->chalk(xpos, 1, trigger, title, true);
	_dr->_vm->_gyro->on(); /*MT*/
}

void headtype::highlight() {
	_dr->_vm->_gyro->off();
	_dr->_vm->_gyro->off_virtual();

	//nosound();
	//setactivepage(cp);
	warning("STUB: Dropdown::headytpe::highlight()");

	_dr->hlchalk(xpos, 1, trigger, title, true);
	{
		_dr->ddm_o.left = xpos;
		_dr->ddm_o.menunow = true;
		_dr->_vm->_gyro->ddmnow = true;
		_dr->ddm_o.menunum = position;
	}
	_dr->_vm->_gyro->cmp = 177; /* Force redraw of cursor. */
}

bool headtype::extdparse(char c) {
	if (c != alttrigger)  
		return true;
	return false;
}






onemenu *onemenu::init(Dropdown *dr) {
	_dr = dr;
	menunow = false;
	_dr->_vm->_gyro->ddmnow = false;
	menunum = 1;
	return this;
}

void onemenu::start_afresh() {
	number = 0;
	width = 0;
	firstlix = false;
	oldy = 0;
	highlightnum = 0;
}

void onemenu::opt(Common::String n, char tr, Common::String key, bool val) {
	int16 l;
	number += 1;
	l = (n + key).size() + 3;
	if (width < l)  width = l;
	{
		optiontype &with = oo[number];
		with.title = n;
		with.trigger = tr;
		with.shortcut = key;
		with.valid = val;
	}
}

void onemenu::displayopt(byte y, bool highlit) {
	warning("STUB: Dropdown::onemenu::displayopt()");
}

void onemenu::display() {
	warning("STUB: Dropdown::onemenu::display()");
}

void onemenu::wipe() {
	warning("STUB: Dropdown::onemenu::wipe()");
}

void onemenu::movehighlight(int8 add) {
	warning("STUB: Dropdown::onemenu::movehighlight()");
}

void onemenu::lightup() {  /* This makes the menu highlight follow the mouse.*/
	warning("STUB: Dropdown::onemenu::lightup()");
	/*if ((_dr->_vm->_gyro->mx < flx1 * 8) || (_dr->_vm->_gyro->mx > flx2 * 8) ||
		(_dr->_vm->_gyro->my <= 12) || (_dr->_vm->_gyro->my > fly - 3))
			return;
	highlightnum = (_dr->_vm->_gyro->my - 13) / 10;
	if (highlightnum == oldy)  return;
	movehighlight(0);*/
	
}

void onemenu::select(byte n) {    /* Choose which one you want. */
	if (! oo[n + 1].valid)  return;
	choicenum = n;
	wipe();

	if (choicenum == number)  choicenum -= 1; /* Off the bottom. */
	if (choicenum > number)  choicenum = 0; /* Off the top, I suppose. */

	_dr->ddm_m.ddms[menunum].do_choose;
}

void onemenu::keystroke(char c) {
	byte fv;
	bool found;
	c = toupper(c);
	found = false;
	for (fv = 1; fv <= number; fv ++) {
		if ((toupper(oo[fv].trigger) == c) && oo[fv].valid) {
			select(fv - 1);
			found = true;
		}
	}
	if (! found)
		_dr->_vm->_gyro->blip();
}





menuset *menuset::init(Dropdown *dr) {
	_dr = dr;
	howmany = 0;
	return this;
}

void menuset::create(char t, Common::String n, char alttrig, func dw, func dc) {
	howmany ++;
	ddms[howmany].init(t, alttrig, n, howmany, dw, dc, _dr);
}

void menuset::update() {
	const bytefield menuspace = {0, 0, 80, 9};
	byte fv, page_, savecp;

	/*setactivepage(3);
	setfillstyle(1, _dr->menu_b);
	bar(0, 0, 640, 9);*/
	_dr->_vm->_graphics->drawBar(0, 0, 640, 10, _dr->menu_b);

	savecp = _dr->_vm->_gyro->cp;
	_dr->_vm->_gyro->cp = 3;

	for (fv = 1; fv <= howmany; fv ++)
		ddms[fv].display();

	for (page_ = 0; page_ <= 1; page_ ++)
		_dr->_vm->_trip->getset[page_].remember(menuspace);

	_dr->_vm->_gyro->cp = savecp;
}

void menuset::extd(char c) {
	byte fv;
	fv = 1;
	while ((fv <= howmany) && (ddms[fv].extdparse(c)))  fv += 1;
	if (fv > howmany)  return;
	getcertain(fv);
}

void menuset::getcertain(byte fv) {
	{
		if (_dr->ddm_o.menunow) {
			_dr->ddm_o.wipe(); /* get rid of menu */
			if (_dr->ddm_o.menunum == ddms[fv].position)  return; /* clicked on own highlight */
		}
		ddms[fv].highlight();
		ddms[fv].do_setup;
	}
}

void menuset::getmenu(int16 x) {
	byte fv;
	fv = 0;
	do {
		fv += 1;
		if ((x > ddms[fv].xpos * 8) && (x < ddms[fv].xright * 8)) {
			getcertain(fv);
			return;
		}
	} while (!(fv > howmany));
}





Dropdown::Dropdown(AvalancheEngine *vm) {
	_vm = vm;
}

void Dropdown::find_what_you_can_do_with_it() {
	switch (_vm->_gyro->thinks) {
	case _vm->_gyro->wine:
	case _vm->_gyro->potion:
	case _vm->_gyro->ink:
		_vm->_gyro->verbstr = Common::String(_vm->_acci->vb_exam) + _vm->_acci->vb_drink;
		break;
	case _vm->_gyro->bell:
		_vm->_gyro->verbstr = Common::String(_vm->_acci->vb_exam) + _vm->_acci->vb_ring;
		break;
	case _vm->_gyro->chastity:
		_vm->_gyro->verbstr = Common::String(_vm->_acci->vb_exam) + _vm->_acci->vb_wear;
		break;
	case _vm->_gyro->lute:
		_vm->_gyro->verbstr = Common::String(_vm->_acci->vb_exam) + _vm->_acci->vb_play;
		break;
	case _vm->_gyro->mushroom:
	case _vm->_gyro->onion:
		_vm->_gyro->verbstr = Common::String(_vm->_acci->vb_exam) + _vm->_acci->vb_eat;
		break;
	case _vm->_gyro->clothes:
		_vm->_gyro->verbstr = Common::String(_vm->_acci->vb_exam) + _vm->_acci->vb_wear;
		break;
	default:
		_vm->_gyro->verbstr = _vm->_acci->vb_exam; /* anything else */
	}
}

void Dropdown::chalk(int16 x, int16 y, char t, Common::String z, bool valid) {
	byte ander;
	if (valid)
		ander = 255;
	else
		ander = 170;

	for (byte fv = 0; fv < z.size(); fv++)
		for (byte ff = 0; ff < 8; ff++) {
			byte pixel = ~(_vm->_gyro->little[z[fv]][ff] & ander); // Note that it's the bitwise NOT operator!
			for (byte bit = 0; bit < 8; bit++) {
				byte pixelBit = (pixel >> bit) & 1;
				*_vm->_graphics->getPixel(x * 8 + fv * 8 + 7 - bit, y + ff) = pixelBit + (pixelBit << 1) + (pixelBit << 2);
				// We don't have to bother with the planes, since they all have the same value. See the original.
				// Note that it's the bitwise OR operator!
			}
		}

	if (! z.contains(t))
		return;
	else {
		byte fv;
		for (fv = 0; z[fv] != t; fv++); // Search for the character in the string.
	
		// Similar to the cycle before.
		byte pixel = ~ ander;
		for (byte bit = 0; bit < 8; bit++) {
			byte pixelBit = (pixel >> bit) & 1;
			*_vm->_graphics->getPixel(x * 8 + fv * 8 + 7 - bit, y + 8) = pixelBit | (pixelBit << 1) | (pixelBit << 2);
		}
	}
}

void Dropdown::hlchalk(int16 x, int16 y, char t, Common::String z, bool valid) {
/* Highlighted. */
	byte fv, ff, p;
	uint16 pageseg;
	byte ander;

	warning("STUB: Dropdown::hlchalk()");
}

/*funcedure say(x,y:int16; t:char; z:Common::String; f,b:byte);
begin;
 settextjustify(0,2); setfillstyle(1,b); setcolor(f);
 bar(x-3,y-1,x+textwidth(z)+3,y+textheight(z));
 chalk(x,y,t,z);
end;*/

void Dropdown::bleep() {
	warning("STUB: Dropdown::bleep()");
}

void Dropdown::parsekey(char r, char re) {
	switch (r) {
	case 0:
	case 224: {
		switch (re) {
		case 'K':
			if (ddm_o.menunum > 1)  {
				ddm_o.wipe();
				ddm_m.getcertain(ddm_o.menunum - 1);
			} else {
				;     /* Get menu on the left-hand side */
				ddm_o.wipe();
				ddm_m.getmenu((ddm_m.howmany - 1)*spacing + indent);
			}
			break;
		case 'M':
			if (ddm_o.menunum < ddm_m.howmany)  {
				ddm_o.wipe();
				ddm_m.getcertain(ddm_o.menunum + 1);
			} else {
				;     /* Get menu on the far right-hand side */
				ddm_o.wipe();
				ddm_m.getmenu(indent);
			}
			break;
		case 'H':
			ddm_o.movehighlight(-1);
			break;
		case 'P':
			ddm_o.movehighlight(1);
			break;
		default:
			ddm_m.extd(re);
		}
	}
	break;
	case 13:
		ddm_o.select(ddm_o.highlightnum);
		break;
	default: {
		if (ddm_o.menunow)
			ddm_o.keystroke(r);
	}
	}
}

/*$F+  *** Here follow all the ddm__ and do__ funcedures for the DDM system. */

void Dropdown::ddm__game() {
	{
		ddm_o.start_afresh();
		ddm_o.opt("Help...", 'H', "f1", true);
		ddm_o.opt("Boss Key", 'B', "alt-B", true);
		ddm_o.opt("Untrash screen", 'U', "ctrl-f7", true);
		ddm_o.opt("Score and rank", 'S', "f9", true);
		ddm_o.opt("About Avvy...", 'A', "shift-f10", true);
		ddm_o.display();
	}
}

void Dropdown::ddm__file() {
	{
		ddm_o.start_afresh();
		ddm_o.opt("New game", 'N', "f4", true);
		ddm_o.opt("Load...", 'L', "^f3", true);
		ddm_o.opt("Save", 'S', "^f2", _vm->_gyro->alive);
		ddm_o.opt("Save As...", 'v', "", _vm->_gyro->alive);
		ddm_o.opt("DOS Shell", 'D', _vm->_gyro->atkey + '1', true);
		ddm_o.opt("Quit", 'Q', "alt-X", true);
		ddm_o.display();
	}
}

void Dropdown::ddm__action() {
	Common::String n;
	n = Common::String(_vm->_gyro->f5_does().c_str() + 2, 253);

	{
		ddm_o.start_afresh();
		if (n == "")
			ddm_o.opt("Do something", 'D', "f5", false);
		else
			ddm_o.opt(Common::String(n.c_str() + 2, 253), n[1], "f5", true);
		ddm_o.opt("Pause game", 'P', "f6", true);
		if (_vm->_gyro->dna.room == 99)
			ddm_o.opt("Journey thither", 'J', "f7", _vm->_trip->neardoor());
		else
			ddm_o.opt("Open the door", 'O', "f7", _vm->_trip->neardoor());
		ddm_o.opt("Look around", 'L', "f8", true);
		ddm_o.opt("Inventory", 'I', "Tab", true);
		if (_vm->_trip->tr[1].xs == _vm->_gyro->walk)
			ddm_o.opt("Run fast", 'R', "^R", true);
		else
			ddm_o.opt("Walk slowly", 'W', "^W", true);
		ddm_o.display();
	}
}

void Dropdown::ddm__people() {
	byte here;
	char fv;

	people = "";
	here = _vm->_gyro->dna.room;

	{
		ddm_o.start_afresh();
		for (fv = '\226'; fv <= '\262'; fv ++)
			if (_vm->_gyro->whereis[fv] == here) {
				ddm_o.opt(_vm->_gyro->getname(fv), _vm->_gyro->getnamechar(fv), "", true);
				people = people + fv;
			}
		ddm_o.display();
	}
}

void Dropdown::ddm__objects() {
	char fv;
	{
		ddm_o.start_afresh();
		for (fv = '\1'; fv <= numobjs; fv ++)
			if (_vm->_gyro->dna.obj[fv])
				ddm_o.opt(_vm->_gyro->get_thing(fv), _vm->_gyro->get_thingchar(fv), "", true);
		ddm_o.display();
	}
}

Common::String Dropdown::himher(char x) {         /* Returns "im" for boys, and "er" for girls.*/
	if (x < 175)
		return "im";
	else
		return "er";
}

void Dropdown::ddm__with() {
	warning("STUB: Dropdown::ddm__with()");
}

/*funcedure ddm__map;
begin;
 with ddm_o do
 begin;
  ddm_o.start_afresh;
  opt('Cancel map','G','f5',true);
  opt('Pause game','P','f6',true);
  opt('Journey thither','J','f7',neardoor);
  opt('Explanation','L','f8',true);
  display;
 end;
end;

funcedure ddm__town;
begin;
 with ddm_o do
 begin;
  ddm_o.start_afresh;
  opt('Argent','A','',true);
  opt('Birmingham','B','',true);
  opt('Nottingham','N','',true);
  opt('Cardiff','C','',true);
  display;
 end;
end;*/

void Dropdown::do__game() {
	switch (ddm_o.choicenum) {
		/* Help, boss, untrash screen. */
	case 0:
		_vm->_lucerna->callverb(_vm->_acci->vb_help);
		break;
	case 1:
		_vm->_lucerna->callverb(_vm->_acci->vb_boss);
		break;
	case 2:
		_vm->_lucerna->major_redraw();
		break;
	case 3:
		_vm->_lucerna->callverb(_vm->_acci->vb_score);
		break;
	case 4:
		_vm->_lucerna->callverb(_vm->_acci->vb_info);
		break;
	}
}

void Dropdown::do__file() {
	switch (ddm_o.choicenum) {
		/* New game, load, save, save as, DOS shell, about, quit. */
	case 0:
		_vm->_lucerna->callverb(_vm->_acci->vb_restart);
		break;
	case 1: {
		_vm->_acci->realwords[2] = "";
		_vm->_lucerna->callverb(_vm->_acci->vb_load);
	}
	break;
	case 2: {
		_vm->_acci->realwords[2] = "";
		_vm->_lucerna->callverb(_vm->_acci->vb_save);
	}
	break;
	case 3:
		_vm->_basher->filename_edit();
		break;
	case 4:
		_vm->_enid->back_to_bootstrap(2);
		break;
	case 5:
		_vm->_lucerna->callverb(_vm->_acci->vb_quit);
		break;
	}
}

void Dropdown::do__action() {
	Common::String n;
	switch (ddm_o.choicenum) {
		/* Get up/pause game/open door/look/inv/walk-run */
	case 0: {
		_vm->_acci->person = _vm->_acci->pardon;
		_vm->_acci->thing = _vm->_acci->pardon;
		n = _vm->_gyro->f5_does();
		_vm->_lucerna->callverb(n[1]);
	}
	break;
	case 1:
		_vm->_lucerna->callverb(_vm->_acci->vb_pause);
		break;
	case 2:
		_vm->_lucerna->callverb(_vm->_acci->vb_open);
		break;
	case 3:
		_vm->_lucerna->callverb(_vm->_acci->vb_look);
		break;
	case 4:
		_vm->_lucerna->callverb(_vm->_acci->vb_inv);
		break;
	case 5: {
		if (_vm->_trip->tr[1].xs == _vm->_gyro->walk)  _vm->_trip->tr[1].xs = _vm->_gyro->run;
		else _vm->_trip->tr[1].xs = _vm->_gyro->walk;
		_vm->_trip->newspeed();
	}
	break;
	}
}

void Dropdown::do__objects() {
	_vm->_lucerna->thinkabout(_vm->_gyro->objlist[ddm_o.choicenum + 1], _vm->_gyro->a_thing);
}

void Dropdown::do__people() {
	_vm->_lucerna->thinkabout(people[ddm_o.choicenum + 1], _vm->_gyro->a_person);
	_vm->_gyro->last_person = people[ddm_o.choicenum + 1];
}

void Dropdown::do__with() {
	_vm->_acci->thing = _vm->_gyro->thinks;

	if (_vm->_gyro->thinkthing) {

		_vm->_acci->thing += 49;

		if (_vm->_gyro->verbstr[ddm_o.choicenum + 1] == _vm->_acci->vb_give)
			_vm->_acci->person = _vm->_gyro->last_person;
		else
			_vm->_acci->person = '\376';

	} else {
		switch (_vm->_gyro->verbstr[ddm_o.choicenum + 1]) {
		case '\144': {
			_vm->_acci->thing = '\144';
			_vm->_lucerna->callverb(_vm->_acci->vb_buy);
			return;
		}
		break; /* Beer */
		case '\145': {
			_vm->_acci->thing = '\62';
			_vm->_lucerna->callverb(_vm->_acci->vb_buy);
			return;
		}
		break; /* Wine */
		case '\146': {
			_vm->_acci->thing = '\146';
			_vm->_lucerna->callverb(_vm->_acci->vb_buy);
			return;
		}
		break; /* Whisky */
		case '\147': {
			_vm->_acci->thing = '\147';
			_vm->_lucerna->callverb(_vm->_acci->vb_buy);
			return;
		}
		break; /* Cider */
		case '\150': {
			_vm->_acci->thing = '\153';
			_vm->_lucerna->callverb(_vm->_acci->vb_buy);
			return;
		}
		break; /* Mead */
		case '\151': {
			_vm->_acci->thing = '\103';
			_vm->_lucerna->callverb(_vm->_acci->vb_buy);
			return;
		}
		break; /* Onion (trader) */
		default: {
			_vm->_acci->person = _vm->_acci->thing;
			_vm->_acci->thing = '\376';
		}
		}
	}
	_vm->_lucerna->callverb(_vm->_gyro->verbstr[ddm_o.choicenum + 1]);
}

/*$F- That's all. Now for the ...bar funcs. */


void Dropdown::standard_bar() {   /* Standard menu bar */
	ddm_m.init(this);
	ddm_o.init(this);
	/* Set up menus */

	ddm_m.create('F', "File", '!', &Avalanche::Dropdown::ddm__file, &Avalanche::Dropdown::do__file); /* same ones in map_bar, below, */
	ddm_m.create('G', "Game", '\42', &Avalanche::Dropdown::ddm__game, &Avalanche::Dropdown::do__game); /* Don't forget to change the */
	ddm_m.create('A', "Action", '\36', &Avalanche::Dropdown::ddm__action, &Avalanche::Dropdown::do__action); /* if you change them */
	ddm_m.create('O', "Objects", '\30', &Avalanche::Dropdown::ddm__objects, &Avalanche::Dropdown::do__objects); /* here... */
	ddm_m.create('P', "People", '\31', &Avalanche::Dropdown::ddm__people, &Avalanche::Dropdown::do__people);
	ddm_m.create('W', "With", '\21', &Avalanche::Dropdown::ddm__with, &Avalanche::Dropdown::do__with);

	ddm_m.update();
}



/*funcedure map_bar; { Special menu bar for the map (screen 99) }
begin;
 ddm_m.init; ddm_o.init;
 with ddm_m do
 begin; { Set up menus }
  create('G','Game','#',ddm__game,do__game);
  create('F','File','!',ddm__file,do__test);
  create('M','Map','2',ddm__map,do__test);
  create('T','Town',#20,ddm__town,do__test);
  update;
 end;
end;*/

void Dropdown::checkclick() {   /* only for when the menu's displayed */
	if (_vm->_gyro->mpress > 0) {
		if (_vm->_gyro->mpy > 10) {
			if (!((ddm_o.firstlix) &&
			   ((_vm->_gyro->mpx >= ddm_o.flx1 * 8) && (_vm->_gyro->mpx <= ddm_o.flx2 * 8) &&
			   (_vm->_gyro->mpy >= 12) && (_vm->_gyro->mpy <= ddm_o.fly)))) {
			     /* Clicked OUTSIDE the menu. */
				if (ddm_o.menunow)
					ddm_o.wipe();
			}    /* No "else"- clicking on menu has no effect (only releasing) */
		} else {
			 /* Clicked on menu bar */
			ddm_m.getmenu(_vm->_gyro->mpx);
		}
	} else {
		;     /* NOT clicked button... */
		if (_vm->_gyro->mrelease > 0) {
			if ((ddm_o.firstlix) &&
			   ((_vm->_gyro->mrx >= ddm_o.flx1 * 8) && (_vm->_gyro->mrx <= ddm_o.flx2 * 8) &&
			   (_vm->_gyro->mry >= 12) && (_vm->_gyro->mry <= ddm_o.fly)))
					ddm_o.select((_vm->_gyro->mry - 13) / 10);
		}
	}
}

void Dropdown::menu_link() {
	if (! ddm_o.menunow)  return;

	_vm->_gyro->check(); /* find mouse coords & click information */
	checkclick(); /* work out click codes */

	/* Change arrow... */

		
	if ((_vm->_gyro->my >= 0) && (_vm->_gyro->my <= 10))
		_vm->_gyro->newpointer(1); /* up-arrow */
	else if ((_vm->_gyro->my >= 11) && (_vm->_gyro->my <= 169)) {
		if ((_vm->_gyro->mx >= ddm_o.flx1 * 8) && (_vm->_gyro->mx <= ddm_o.flx2 * 8)
			&& (_vm->_gyro->my > 10) && (_vm->_gyro->my <= ddm_o.fly))
			_vm->_gyro->newpointer(3); /* right-arrow */
		else
			_vm->_gyro->newpointer(4); /* fletch */
	} else if ((_vm->_gyro->my >= 169) && (_vm->_gyro->my <= 200))
		_vm->_gyro->newpointer(2); /* screwdriver */

	if (! ddm_o.menunow)
		return;

	ddm_o.lightup();
}


} // End of namespace Avalanche.