/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * ncurses_main.c
 * Copyright (C) Steffen Pohle 2009 <steffen@gulpe.de>
 * 
 * main.c 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 3 of the License, or
 * (at your option) any later version.
 * 
 * main.c 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, see <http://www.gnu.org/licenses/>.
 */
/*
 * convert_main.c
 * Copyright (C) Steffen Pohle 2009 <steffen@gulpe.de>
 * 
 * main.c 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 3 of the License, or
 * (at your option) any later version.
 * 
 * main.c 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, see <http://www.gnu.org/licenses/>.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <curses.h>

#include "memoryleak.h"
#include "map.h"
#include "ncurses_port.h"
#include "system.h"

char curfile[LEN_FILENAME];

struct menuentry {
	char key;
	char name[LEN_FILENAME];
};


int getchar ();


/* call this function always at the end of programm */
void main_wnd_quit() {
	endwin();
}


void information () {
}


void mvsetflags (int y, int x, int *flags, char *fltext) {	
	int i, c, pos = 1, max = 1, key, dpos = 0;
	char *fn1;
	char *fn2;
	char txt1[255];

	do {
		dpos = 0;
		mvprintw (y, x, "                                                 ");
		for (c = 1,	fn1 = fltext; (c < 0xFFFF && fn1 != NULL); c *= 2) {
			memset (txt1, 0x0, 255);
			fn2 = strchr (fn1, '\n');
			if (fn2 == NULL) i = strlen (fn1);
			else i = fn2-fn1;
			if (*flags & c) attrset(COLOR_PAIR(pos == c ? 2 : 1) | A_BOLD);
			else attrset(COLOR_PAIR(pos == c ? 2 : 1));

			strncpy (txt1, fn1, i);
			mvprintw (y, x+dpos, "%s", txt1);
			dpos += i+2;
			if (fn2 != NULL) fn2 += 1;
			fn1 = fn2;
		}
		refresh ();
		max = c;
		key = getchar ();
		if (key == '\n' || key == ' ') {
			if (*flags & pos) *flags &= (0xFFFF-pos);
			else  *flags |= pos;
		}
		if (key == KEY_LEFT) pos /= 2;
		if (key == KEY_RIGHT) pos *= 2;
			
		if (pos < 1) pos = 1;
		if (pos >= max) pos = max / 2;
	} while (key != 'q' && key != KEY_CLOSE && key != KEY_CANCEL && key != KEY_END);
}


void inputenabled (int enabled) {
	if (enabled) {
		echo ();
		curs_set(1);
		nodelay (stdscr, 0);
		keypad(stdscr, 0);
	}
	else {
		keypad(stdscr, 1);
		noecho ();
		curs_set(0);
		nodelay (stdscr, 1);
	}
}



int getchar () {
	int c;
	do {
		c = getch ();
		refresh();
		usleep (1000);
	} while ( c == -1 );
	return c;
}


void editway () {
	struct map_hash *mh = NULL;
	struct map_way *mw = NULL;
	struct map_hashpos hpos = { 0,0 };
	unsigned long long int way_id = 0;
	unsigned int way_subid = 0;
	int c, i;

	struct menuentry menu[] = {
		{ 'j', N_("jump to node") },
		{ 'f', N_("change flags") },
		{ 'n', N_("name") },
		{ 'r', N_("change reference") },
		{ 'q', N_("quit") },
	};

	do {
		clear();
		attrset(COLOR_PAIR(1));
		mvprintw(0,1, "char: %d   way:%lld:%d", c, way_id, way_subid);
		mvprintw(2,1, _(" ilon: %d"), hpos.ilon);
		mvprintw(3,1, _(" ilat: %d"), hpos.ilat);
		mvprintw(2,21, _("   id: %lld") , way_id);
		mvprintw(3,21, _("subid: %d"), way_subid);
		refresh();
		if (way_id == 0 || c == '\n') {
			inputenabled (1);
			mvprintw(1,1, _("please enter way data"));
			attrset(COLOR_PAIR(2) | A_BOLD);
			mvscanw (2, 8, "%d", &hpos.ilon);
			mvscanw (3, 8, "%d", &hpos.ilat);
			mvscanw (2, 28, "%lld", &way_id);
			mvscanw (3, 28, "%d", &way_subid);
			inputenabled (0);
		}
		mh = map_hash_geti (hpos.ilon, hpos.ilat, MHLOAD_RELOAD);
		if (mh == NULL) {
			attrset(COLOR_PAIR(4));
			mvprintw (1, 1, _("mhash not found.                     "));
			way_id = 0;
			way_subid = 0;
		}
		else {
			mw = map_way_find (mh, way_id, way_subid);
			if (mw == NULL) {
				attrset(COLOR_PAIR(4));
				mvprintw (1, 1, _("way not found.                       "));
				way_id = 0;
				way_subid = 0;
			}
		}
		if (mw) {
			attrset(COLOR_PAIR(1));
			mvprintw (5, 1, "  Name: ");
			mvprintw (6, 1, "   Ref: ");
			mvprintw (7, 1, " Flags: ");
			mvprintw (8, 1, " n_cnt: ");
			mvprintw (8, 21, " p_cnt: ");
			
			attrset(COLOR_PAIR(2));
			mvprintw (5, 10, "%s", mw->name);
			mvprintw (6, 10, "%s", mw->ref);
			mvprintw (7, 10, "%s", flags2text(mw->flags, "oneway\nplaned\nroundabout"));
			mvprintw (8, 10, "%d", mw->n_cnt);
			mvprintw (8, 30, "%d", mw->p_cnt);
		}

		for (i = 0; i < sizeof (menu) / sizeof (struct menuentry); i++) {
			attrset(COLOR_PAIR(3));
			mvprintw(0+i, 45, "%c", menu[i].key);
			attrset(A_BOLD | COLOR_PAIR(2));
			mvprintw(0+i, 50, "%s", menu[i].name);
		}
		c = getchar ();
		if (c == 'f' && mw) {
			i = mw->flags;
			mvsetflags (7,10, &i, "oneway\nplaned\nroundabout");
			mw->flags = i;
			map_way_add_to_hash (mh, mw);
		}
		if (c == 'n' && mw) {
			inputenabled (1);
			attrset(COLOR_PAIR(2)|A_BOLD);
			mw->name[0] = 0;
			mvgetnstr (5, 10, mw->name, MAP_W_NAMELEN);
			inputenabled (0);
			map_way_add_to_hash (mh, mw);
		}
		if (c == 'r' && mw) {
			inputenabled (1);
			attrset(COLOR_PAIR(2)|A_BOLD);
			mvgetnstr (6, 10, mw->ref, MAP_W_NAMELEN);
			inputenabled (0);
			map_way_add_to_hash (mh, mw);
		}
	} while (c != 'q');
}


void mainmenu () {
	int c, i;
	
	struct menuentry menu[] = {
		{ 'w', N_("Edit Way") },
		{ ' ', "" },
		{ 'd', N_("Defrag Data") },
		{ 's', N_("Sort Search Data") },
		{ ' ', "" },
		{ 'i', N_("Information") },
		{ ' ', "" },
		{ 'q', N_("Quit Programm") }
	};
	
	do {
		clear();
		attrset(COLOR_PAIR(1));
		color_set(2, 0);
		refresh();
		attrset(COLOR_PAIR(3));
		mvprintw(1,1, "---------------------------------------------------------------------");
		attrset(A_BOLD | COLOR_PAIR(2));
		mvprintw(2,1, " sposmedit");

		for (i = 0; i < sizeof (menu) / sizeof (struct menuentry); i++) {
			attrset(COLOR_PAIR(3));
			mvprintw(5+i, 5, "%c", menu[i].key);
			attrset(A_BOLD | COLOR_PAIR(2));
			mvprintw(5+i, 10, "%s", menu[i].name);
		}
	
		refresh();
		c = getchar ();

		if (c == 'q') break;
		if (c == 'w') editway();
		if (c == 'i') information();
		if (c == 'd') {
			clear ();
			attrset(COLOR_PAIR(1) | A_BOLD);
			mvprintw(1,1, "Defrag all MapData");
			refresh ();
			map_defrag ();
		}
		if (c == 's') { 
			clear ();
			attrset(COLOR_PAIR(1) | A_BOLD);
			mvprintw(1,1, "Sort search data");
			refresh ();
			map_search_sort ();
		}
	} while ( c != -1 );
}


int main (int argc, char *argv[]) {
	struct stat sb;

	ml_init();
#ifdef ENABLE_NLS
	bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
	textdomain (GETTEXT_PACKAGE);
#endif

	/* check for the cache path and the map path */
	if (stat(cfg.cachepath, &sb) == -1) {
		mkdir (cfg.cachepath, 0755);
	}

	if (stat(cfg.mappath, &sb) == -1) {
		mkdir (cfg.mappath, 0755);
	}
	
	config_init ();
	config_load ();

	map_init ();
	main_wnd_startall (); 
	
	if (argc > 1) {
		strncpy (curfile, argv[1], LEN_FILENAME);
		osm_loadfile (curfile);
	}
	else {
		mainmenu ();
	}

	map_save_all ();
	config_save ();
	return 0;
};


void main_wnd_startall () {
	initscr();
	atexit(main_wnd_quit);
	noecho ();
	curs_set(0);
	nodelay (stdscr, 1);
	start_color();
	init_pair(1, COLOR_GREEN, COLOR_BLACK); 
	init_pair(2, COLOR_WHITE, COLOR_BLACK); 
	init_pair(3, COLOR_CYAN, COLOR_BLACK); 
	init_pair(4, COLOR_RED, COLOR_BLACK); 
	bkgd(COLOR_PAIR(1));
};


void main_wnd_loop (long long int cur, long long int max) {
	struct memoryleak_info mi;
	static time_t timeout = 0;
	int ways, hash, i, x, y;
	
	if (timeout+1 > time (NULL)) return;
	timeout = time(NULL);
	
	ml_get_stats (&mi);

	clear();
	attrset(COLOR_PAIR(1));
	mvprintw(0,1, "Converting %s file.", curfile);

	attrset(A_BOLD | COLOR_PAIR(2));
	mvprintw(0,12, "%s", curfile);
	
	attrset(COLOR_PAIR(3));
	mvprintw(1,1, "---------------------------------------------------------------------");
	mvprintw(2,1, " Current File Pos:         %%            |Memory Used:");
	mvprintw(3,1, "            nodes:                      |     Blocks:");
	mvprintw(4,1, "             ways:                      |");
	
	attrset(A_BOLD | COLOR_PAIR(2));
	mvprintw(2, 19, "%3.3f", osm_file_pos);
	mvprintw(3, 19, "%lld", osm_nodes_cnt);
	mvprintw(4, 19, "%lld", osm_ways_cnt);	

	mvprintw(5, 1, "Status: %-5d of %-5d", cur, max);	

	if (mi.size < 10*1024)	mvprintw(2, 55, "%lld bytes", mi.size);
	else if (mi.size < 10*1024*1024) mvprintw(2, 55, "%lld kbytes", mi.size/1024);
	else mvprintw(2, 55, "%lld Mbytes", mi.size/(1024*1024));
	mvprintw(3, 55, "%lld", mi.blocks);
	
	if (max == -2) {
		/* searching way ... give informations */
		attrset(A_BOLD | COLOR_PAIR(1));
		mvprintw(5, 40, "adding nodes to the way id:");
		attrset(A_BOLD | COLOR_PAIR(2));
		mvprintw(5, 68, "%lld", cur);
	}

	osm_convert_info ();

	attrset(A_BOLD | COLOR_PAIR(3));
	mvprintw(6,50, "MAP Hash Information");
	attrset(COLOR_PAIR(3));
	mvprintw(7, 41, "+------------------------------------+");
	for (i = 0; i < 12; i++) mvprintw(8+i, 41, "|                                    |");
	mvprintw(19, 41, "+------------------------------------+");
	mvprintw(20, 41, " hash cnt:       ways cnt:");
	attrset(A_BOLD | COLOR_PAIR(2));
	for (i = 0, hash = 0, ways = 0; i < mhash_max; i++) {
		if (mhash[i]) {
			x = (float) (36*(map_igeo2geo(mhash[i]->pos.ilon)+160.0)/360.0);
			y = (float) (10*((-map_igeo2geo(mhash[i]->pos.ilat))+90.0)/180.0);
			mvprintw(8+y, 42+x, "*");

			hash++;
			ways += mhash[i]->wayscnt;
		}
	}
	mvprintw(20, 51, "%d", hash);
	mvprintw(20, 67, "%d", ways);
	
	refresh ();
};


void main_wnd_update () {
};

void draw () {
};

