/*
 * This file is in the public domain.
 * Use it as you wish.
*/
#include "inkview.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <regex.h>
#include <zip.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/HTMLtree.h>
#include <unistd.h>

#define FONT_SIZE 24
#define BUFFER 1024
#define SBUFFER 128
#define SENSIBILITY 40
#define QUIT_ZONE 80
#define CENTER_ZONE 300
#define MARGINX 25
#define MARGINY 20
#define MENU_MARGIN 30



static int keys_handler(int type, int par1, int par2);
//extern const ibitmap border_x, border_y, separator, title_separator, up_separator, no_cover;
extern const ibitmap separator, no_cover;
const ibitmap * cover;
char *translation[][12]={
			{"fr","Série","Tome","Traduction","Illustration","Publication","Date de publication","Mention légale","Source","Thème(s)","ISBN","Langue"},
			{"de","Serie","Nummer","Übersetzung","Illustration","Verlag","Veröffentlichung","Rechte","Quelle","Genre(s)","ISBN","Sprache"},
			{"ru","Серия","Индекс","Перевод","Иллюстрации","Издательство","Дата издания","Права","Источник","Автор(ы)","ISBN","Язык"},
			{"uk","Серія","Індекс","Переклад","Ілюстрації","Видавництво","Дата видання","Права","Джерело","Автор(и)","ISBN","Мова"},
			{"nl","Serie","Index","Vertaler","Illustrator","Uit gever","Publicatiedatum","Rechten","Bron","Onderwerp(en)","ISBN","Taal"},
			{"cs","Série","Číslo","Překladatel","Ilustrátor","Vydavatel","Datum vydání","Rights","Zdroj","Žánr(y)","ISBN","Jazyk"},
			{"en","Series","Index","Translator","Illustrator","Publication","Date of publication","Rights","Source","Subject(s)","ISBN","Language"},
		};
struct metadata {
	char title[BUFFER];
	char author[BUFFER];
	char author_formal_name[BUFFER];
	char translator[BUFFER];
	char illustrator[BUFFER];
	char language[BUFFER];
	char subject[BUFFER];
	char publisher[BUFFER];
	char date[BUFFER];
	char rights[BUFFER];
	char description[BUFFER*20];
	char source[BUFFER];
	char generator[BUFFER];
	char serie[BUFFER];
	char number[BUFFER];
	char isbn[BUFFER];
};

char tempbuf[BUFFER*20];
char ebook[BUFFER];
struct metadata meta;
int r;
ifont* tbFont = NULL;
ifont* tFont = NULL;
ifont* aFont = NULL;
ifont* bFont = NULL;
ifont* pFont = NULL;
ifont* mFont = NULL;
int screen_y=0;
int title_y=0;
int title_h=0;
int author_y=0;
int author_h=0;
int tempbuf_y=0;
int tempbuf_h=0;
int description_y=0;
int description_h=0;
int total_h=0;
int base_y=0;
int cover_y=0;
static icanvas* pCanvas;
char apptab[50][SBUFFER];
int appcount=0;
int menu_h=0;
int menu_w=0;
int menu_case=0;
int casemenu_h=0;
int txtmenu_h=0;
int istextnode=0;

//delete multiple space caracters
void compress_spaces(char *str)
{
	char *dst = str;

	for (; *str; ++str) {
		*dst++ = *str;
			if (isspace(*str)) {
				do ++str; while (isspace(*str));
					--str;
			}
	}
	*dst = 0;
}

//remove string
char * str_remove (char * const str, char old)
{
	char * ptr;
	for(ptr=str; *ptr;++ptr)
	{
		if (*ptr == old)
			strcpy(ptr,ptr+1);
	}
	return str;
}

//replace string
char * str_replace (char * const str, char old,char new)
{
	char * ptr;
	for(ptr=str; *ptr;++ptr)
	{
		if (*ptr == old)
		*ptr=new;
	}
	return str;
}

char *replace_str(const char *str, const char *old, const char *new)
{
	char *ret, *r;
	const char *p, *q;
	size_t oldlen = strlen(old);
	size_t count, retlen, newlen = strlen(new);

	if (oldlen != newlen) {
		for (count = 0, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen)
			count++;
		/* this is undefined if p - str > PTRDIFF_MAX */
		retlen = p - str + strlen(p) + count * (newlen - oldlen);
	} else
		retlen = strlen(str);

	if ((ret = malloc(retlen + 1)) == NULL)
		return NULL;

	for (r = ret, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) {
		/* this is undefined if q - p > PTRDIFF_MAX */
		ptrdiff_t l = q - p;
		memcpy(r, p, l);
		r += l;
		memcpy(r, new, newlen);
		r += newlen;
	}
	strcpy(r, p);

	return ret;
}

//the main draw fonction
void draw_font(int move)
{
//	DrawBitmap((pCanvas->width/2)-(up_separator.width/2),base_y-move, &up_separator);

	//adapt font to title lenght
	if (strlen(meta.title)<20)
		SetFont(tbFont,BLACK);
	else
		SetFont(tFont,BLACK);

	DrawTextRect(MARGINX, title_y-move,pCanvas->width-(MARGINX*2),title_h, meta.title, ALIGN_CENTER);
	
	SetFont(aFont,BLACK);
	DrawTextRect(MARGINX, author_y-move,pCanvas->width-(MARGINX*2),author_h, meta.author, ALIGN_CENTER);
	
	DrawBitmap((pCanvas->width/2)-(separator.width/2),author_y-move+author_h, &separator);
	
	SetFont(bFont,BLACK);
	DrawBitmap(MARGINX+1,cover_y-move, cover);
	DrawRect(MARGINX,cover_y-move-1,152,202,BLACK);

	DrawTextRect((MARGINX+(MARGINX/2))+cover->width,tempbuf_y-move,pCanvas->width-(MARGINX*2+(MARGINX/2)+cover->width),tempbuf_h, tempbuf, ALIGN_LEFT);

	DrawBitmap((pCanvas->width/2)-(separator.width/2),tempbuf_y-move+tempbuf_h+1, &separator);

	SetFont(pFont,BLACK);
	DrawTextRect(MARGINX, description_y-move,pCanvas->width-(MARGINX*2),description_h,meta.description, ALIGN_FIT);

	base_y=base_y-move;
	title_y=title_y-move;
	author_y=author_y-move;
	cover_y=cover_y-move;
	tempbuf_y=tempbuf_y-move;
	description_y=description_y-move;
}

//the first draw fonction call at start
void initial_draw()
{
	ClearScreen();
	SetClip(0,0,pCanvas->width,pCanvas->height);
//	DrawBitmap(0, 0, &border_y);
//	DrawBitmap(border_y.width, 0, &border_x);
	
//	StretchBitmap (pCanvas->width-(border_y.width),0,border_y.width,border_y.height,&border_y,XMIRROR);
//	StretchBitmap (border_y.width,pCanvas->height-(border_x.height),border_x.width,border_x.height,&border_x,YMIRROR);
	
	DrawRect(13,13,pCanvas->width-26,pCanvas->height-26,BLACK);
	DrawRect(16,16,pCanvas->width-32,pCanvas->height-32,BLACK);
	
	SetClip(MARGINX,MARGINY,pCanvas->width-(MARGINX*2),pCanvas->height-(MARGINY*2));
	
	draw_font(0);
}

void draw_quickmenu()
{
	int menu_y=(pCanvas->height/2)-(menu_h/2);
	//used to center text verticaly
	int txtmenu_y=0;
	int i=0;
	
	FillArea((pCanvas->width/2)-(menu_w/2),menu_y,menu_w,menu_h, WHITE);
	DrawRect((pCanvas->width/2)-(menu_w/2),menu_y,menu_w,menu_h, BLACK);
	
	SetFont(mFont,BLACK);
	for(i=0;i<appcount;i++)
	{
		txtmenu_y=menu_y+(i*casemenu_h)+((casemenu_h-txtmenu_h)/2);
		DrawTextRect((pCanvas->width/2)-(menu_w/2),txtmenu_y,menu_w,txtmenu_h, apptab[i], ALIGN_CENTER);
		DrawLine((pCanvas->width/2)-(menu_w/2),menu_y+i*casemenu_h,(pCanvas->width/2)-(menu_w/2)+menu_w,menu_y+i*casemenu_h,BLACK);
	}
	PartialUpdate((pCanvas->width/2)-(menu_w/2),menu_y,menu_w,menu_h);
}

void invert_quickmenu_case(int selected_case)
{
	InvertArea((pCanvas->width/2)-(menu_w/2),(pCanvas->height/2)-(menu_h/2)+((selected_case-1)*casemenu_h),menu_w,casemenu_h);
	DitherArea((pCanvas->width/2)-(menu_w/2),(pCanvas->height/2)-(menu_h/2)+((selected_case-1)*casemenu_h),menu_w,casemenu_h,2, DITHER_THRESHOLD);
	PartialUpdate((pCanvas->width/2)-(menu_w/2),(pCanvas->height/2)-(menu_h/2)+((selected_case-1)*casemenu_h),menu_w,casemenu_h);
}

//quick menu event handling
int quickmenu_handler(int type, int par1, int par2) {

	if (type == EVT_SHOW) 
	{
		menu_h=0;
		menu_w=0;
		int i=0;
		txtmenu_h=0;
		casemenu_h=0;
				
		//get the max caracter width of our app menu
		for(i=0;i<appcount;i++)
		{
			if(StringWidth(apptab[i])>menu_w)
				menu_w=StringWidth(apptab[i]);
		}
		
		//add a standard margin
		menu_w=menu_w+(MENU_MARGIN*2);
		
		//get the max caracter height of our app
		for(i=0;i<appcount;i++)
		{
			if(TextRectHeight(menu_w,apptab[i],ALIGN_CENTER)>txtmenu_h)
				txtmenu_h=TextRectHeight(menu_w,apptab[i],ALIGN_CENTER);
		
		}
		//add a standard margin
		casemenu_h=txtmenu_h+MENU_MARGIN;
		menu_h=appcount*casemenu_h;

		draw_quickmenu();
	}

	if (type==EVT_POINTERDOWN && (par1<(pCanvas->width/2)-(menu_w/2) || par1>(pCanvas->width/2)+(menu_w/2) || par2>(pCanvas->height/2)+(menu_h/2) || par2<(pCanvas->height/2)-(menu_h/2) ))
	{	
		//return to the standart handler
		SetEventHandler(keys_handler);
	}

	if (type==EVT_POINTERDOWN && (par1>=(pCanvas->width/2)-(menu_w/2) && par1<=(pCanvas->width/2)+(menu_w/2) && par2<=(pCanvas->height/2)+(menu_h/2) && par2>=(pCanvas->height/2)-(menu_h/2) ))
	{	
		//what is the selected case 
		menu_case=0;
		int i;
		
		for (i=(pCanvas->height/2)-(menu_h/2);i<=par2;i=i+casemenu_h)
		{
			menu_case++;
		}
		draw_quickmenu();
		invert_quickmenu_case(menu_case);
	}

	if (type==EVT_POINTERUP && (par1>=(pCanvas->width/2)-(menu_w/2) && par1<=(pCanvas->width/2)+(menu_w/2) && par2<=(pCanvas->height/2)+(menu_h/2) && par2>=(pCanvas->height/2)-(menu_h/2) ))
	{
		if(menu_case!=0)
		{	
			ShowHourglass();
			//NotifyConfigChanged() cost too much;
			SetFileHandler(ebook,apptab[menu_case-1]);
			//open our book with the selected application
			OpenBook(ebook,NULL,OB_ADDTOLAST|OB_NONEWTASK);
		}
	}

	if (type==EVT_KEYPRESS  && (par1==KEY_RIGHT || par1==KEY_UP || par1==KEY_NEXT ))
	{
		menu_case++;
		if (menu_case>appcount)
			menu_case=1;
		
		draw_quickmenu();
		invert_quickmenu_case(menu_case);
	}

	if (type==EVT_KEYPRESS  && (par1==KEY_LEFT || par1==KEY_DOWN || par1==KEY_PREV ))
	{
		menu_case--;
		if (menu_case<1)
			menu_case=appcount;
		
		draw_quickmenu();
		invert_quickmenu_case(menu_case);
	}

	if (type==EVT_KEYPRESS  && par1!=KEY_MENU  && par1!=KEY_OK && par1!=KEY_LEFT && par1!=KEY_DOWN && par1!=KEY_PREV && par1!=KEY_RIGHT && par1!=KEY_UP && par1!=KEY_NEXT )
	{
		SetEventHandler(keys_handler);
	}
	
	if (type==EVT_KEYPRESS  && (par1==KEY_MENU || par1==KEY_OK))
	{
		SendEvent(GetEventHandler(),EVT_POINTERUP,pCanvas->width/2,pCanvas->height/2);
	}
	
 return 0;
}


int keys_handler(int type, int par1, int par2)
{
	int move_y=0;
	
	if (type==EVT_INIT)
	{
 		pCanvas = GetCanvas();
		
		tbFont = OpenFont("LiberatioSans", FONT_SIZE+25, 1);
		tFont = OpenFont("LiberationSans", FONT_SIZE+18, 1);
		aFont = OpenFont("LiberationSans", FONT_SIZE+10, 1);
		bFont = OpenFont("LiberationSans", FONT_SIZE-2, 1);
 		pFont = OpenFont("LiberationSans", FONT_SIZE, 1);
		mFont = OpenFont("DroidSans", FONT_SIZE, 1);
			
		//tempbuf used again to show metadata
		strcpy(tempbuf,"");
		
		char *lang;
		//reading default language
		iconfig * cfg=GetGlobalConfig();
		lang=ReadString (cfg,"language","en");
		int i=0;
		while(strcmp(lang,translation[i][0])!=0 && strcmp(translation[i][0],"en")!=0) i++;
		
		if (strlen(meta.serie)>0)
			sprintf(tempbuf,"%s%s: %s\n",tempbuf,translation[i][1],meta.serie);
		if (strlen(meta.number)>0 && strlen(meta.serie)>0)
			sprintf(tempbuf,"%s%s: %s\n",tempbuf,translation[i][2],meta.number);
		if (strlen(meta.translator)>0)
			sprintf(tempbuf,"%s%s: %s\n",tempbuf,translation[i][3],meta.translator);
		if (strlen(meta.illustrator)>0)
			sprintf(tempbuf,"%s%s: %s\n",tempbuf,translation[i][4],meta.illustrator);
		if (strlen(meta.publisher)>0)
			sprintf(tempbuf,"%s%s: %s\n",tempbuf,translation[i][5],meta.publisher);
		if (strlen(meta.date)>0)
			sprintf(tempbuf,"%s%s: %s\n",tempbuf,translation[i][6],meta.date);
		if (strlen(meta.rights)>0)
			sprintf(tempbuf,"%s%s: %s\n",tempbuf,translation[i][7],meta.rights);
		if (strlen(meta.source)>0)
			sprintf(tempbuf,"%s%s: %s\n",tempbuf,translation[i][8],meta.source);
		if (strlen(meta.subject)>0)
			sprintf(tempbuf,"%s%s: %s\n",tempbuf,translation[i][9],meta.subject);
		if (strlen(meta.isbn)>0)
			sprintf(tempbuf,"%s%s: %s\n",tempbuf,translation[i][10],meta.isbn);
		if (strlen(meta.language)>0)
			sprintf(tempbuf,"%s%s: %s\n",tempbuf,translation[i][11],meta.language);
		

		if (strlen(meta.title)<20)
			SetFont(tbFont,BLACK);
		else
			SetFont(tFont,BLACK);
		title_h=TextRectHeight(pCanvas->width-(MARGINX*2),meta.title,ALIGN_CENTER);
		
		SetFont(aFont,BLACK);
		author_h=TextRectHeight(pCanvas->width-(MARGINX*2),meta.author,ALIGN_CENTER);
		SetFont(bFont,BLACK);
		tempbuf_h=TextRectHeight((pCanvas->width)-(MARGINX+cover->width+(MARGINX/2)+MARGINX),tempbuf,ALIGN_LEFT);
		if(tempbuf_h<=cover->height)
			tempbuf_h=cover->height;

		SetFont(pFont,BLACK);
		description_h=TextRectHeight(pCanvas->width-(MARGINX*2),meta.description,ALIGN_FIT);
		
		//each block position depends of the other one
		base_y=MARGINY;
//		title_y=base_y+up_separator.height;
		title_y=base_y;
		author_y=title_y+title_h;
		tempbuf_y=author_y+author_h+separator.height;
		description_y=tempbuf_y+tempbuf_h+separator.height;
		
		if(tempbuf_h<=cover->height)
			cover_y=tempbuf_y;
		else
			cover_y=tempbuf_y+((tempbuf_h-cover->height)/2);

//		total_h=up_separator.height+title_h+author_h+title_separator.height+tempbuf_h+separator.height+description_h;
		total_h=title_h+author_h+separator.height+tempbuf_h+separator.height+description_h;
		initial_draw();
		FullUpdate();
	}
	    
	if (type==EVT_SHOW)
	{
		initial_draw();
		PartialUpdate(0,0,pCanvas->width,pCanvas->height);
	}

	//par2 could be corrupted when using emulator, so we check it  
	if (type==EVT_POINTERMOVE && ( par2 >= screen_y+SENSIBILITY || par2 <= screen_y-SENSIBILITY) && par2 > 0 &&  par2 < pCanvas->height)
	{
		move_y=screen_y-par2;
		ClearScreen();
		draw_font(move_y);
		DitherArea(MARGINX, base_y,pCanvas->width-(MARGINX*2),total_h,2, DITHER_THRESHOLD);	
		PartialUpdate(MARGINX,MARGINY,pCanvas->width-(MARGINX*2),pCanvas->height-(MARGINY*2));
		screen_y=screen_y-move_y;
	}  

	if (type==EVT_POINTERDOWN && par1>=QUIT_ZONE && par2>=QUIT_ZONE)
	{	
		screen_y=par2;
	}
	  
	if (type==EVT_POINTERUP && par1>=QUIT_ZONE && par2>=QUIT_ZONE)
	{
		ClearScreen();
		DitherArea(MARGINX, base_y,pCanvas->width-(MARGINX*2),total_h,2, DITHER_DIFFUSION);
		draw_font(0);
		PartialUpdate(MARGINX,MARGINY,pCanvas->width-(MARGINX*2),pCanvas->height-(MARGINY*2));
	}
 
 	if (type==EVT_POINTERUP && par1<=(pCanvas->width/2)+(CENTER_ZONE/2) && par1>=(pCanvas->width/2)-(CENTER_ZONE/2) && par2<=(pCanvas->height/2)+(CENTER_ZONE/2) && par2>=(pCanvas->height/2)-(CENTER_ZONE/2))
	{	
		//it is now the quick menu that handles events
		SetEventHandler(quickmenu_handler);
	}
 
	if (type==EVT_EXIT)
	{	
		CloseFont(tbFont);
		CloseFont(tFont);
		CloseFont(aFont);
		CloseFont(bFont);
		CloseFont(pFont);
		CloseFont(mFont);
		pFont = NULL;
		tFont = NULL;
		mFont = NULL;
		tbFont =NULL;
		aFont=NULL;
		bFont=NULL;	
	}

	if (type==EVT_KEYPRESS  && (par1==KEY_LEFT || par1==KEY_DOWN || par1==KEY_PREV ))
	{
		//we simulate a center touch in y and a down mouvement
		screen_y=pCanvas->height/2;
		SendEvent(GetEventHandler(),EVT_POINTERMOVE,pCanvas->width,screen_y+SENSIBILITY);
		SendEvent(GetEventHandler(),EVT_POINTERUP,pCanvas->width,pCanvas->height/2);
	}

	if (type==EVT_KEYPRESS  && (par1==KEY_RIGHT || par1==KEY_UP || par1==KEY_NEXT ))
	{
		//we simulate a center touch in y and a up mouvement
		screen_y=pCanvas->height/2;
		SendEvent(GetEventHandler(),EVT_POINTERMOVE,pCanvas->width,screen_y-SENSIBILITY);
		SendEvent(GetEventHandler(),EVT_POINTERUP,pCanvas->width,pCanvas->height/2);
	}

	if ((type==EVT_POINTERDOWN && par1<QUIT_ZONE && par2<QUIT_ZONE))
	{
		CloseApp();
	}

	if ((type==EVT_KEYPRESS && par1!=KEY_RIGHT && par1!=KEY_LEFT && par1!=KEY_DOWN && par1!=KEY_UP && par1!=KEY_NEXT && par1!=KEY_PREV && par1!=KEY_MENU && par1!=KEY_OK))
	{
		CloseApp();
	}
	if (type==EVT_KEYPRESS  && (par1==KEY_MENU || par1==KEY_OK))
	{
		SetEventHandler(quickmenu_handler);
	}

	return 0;
}

void afficher_noeud(xmlNodePtr noeud) {
	if (noeud->type == XML_ELEMENT_NODE) {
//Message(ICON_ERROR,"Fatal error",xmlNodeGetContent(noeud),1000);
		if (noeud->children != NULL && noeud->children->type == XML_TEXT_NODE) 
		{
			xmlChar *contenu = xmlNodeGetContent(noeud);
			istextnode=1;
			sprintf(meta.description,"%s%s",meta.description,contenu);
			xmlFree(contenu);
		}
		
		if ((!xmlStrcmp(noeud->name, (const xmlChar *)"br")))
		{
			strcat(meta.description,"\n");
		}
	
		if ((!xmlStrcmp(noeud->name, (const xmlChar *)"div") ||
		(!xmlStrcmp(noeud->name, (const xmlChar *)"p")) ||
		(!xmlStrcmp(noeud->name, (const xmlChar *)"h1")) ||
		(!xmlStrcmp(noeud->name, (const xmlChar *)"h2")) ||
		(!xmlStrcmp(noeud->name, (const xmlChar *)"h3")) ||
		(!xmlStrcmp(noeud->name, (const xmlChar *)"h4")) ||
		(!xmlStrcmp(noeud->name, (const xmlChar *)"h5")) ||
		(!xmlStrcmp(noeud->name, (const xmlChar *)"h6")) ||
		(!xmlStrcmp(noeud->name, (const xmlChar *)"pre")) ||
		(!xmlStrcmp(noeud->name, (const xmlChar *)"blockquote")) ||
		(!xmlStrcmp(noeud->name, (const xmlChar *)"address"))) &&
		istextnode==1)
		{
			strcat(meta.description,"\n");
			istextnode=0;
		}
    }
}

typedef void (*fct_parcours_t)(xmlNodePtr);

void parcours_prefixe(xmlNodePtr noeud, fct_parcours_t f) {
	xmlNodePtr n;

	for (n = noeud; n != NULL; n = n->next) {
		f(n);
		if ((n->type == XML_ELEMENT_NODE) && (n->children != NULL)) {
			parcours_prefixe(n->children, f);
		}
	}
}

void parcours_postfixe(xmlNodePtr noeud, fct_parcours_t f) {
	xmlNodePtr n;
	
	for (n = noeud; n != NULL; n = n->next) {
		if ((n->type == XML_ELEMENT_NODE) && (n->children != NULL)) {
			parcours_postfixe(n->children, f);
		}
		f(n);
	}
}

/* Recursive function that parse the XML structure */
static void parse_xml(xmlNode * a_node, xmlDoc * doc)
{
	xmlNode *cur_node = NULL;

	for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
		if (cur_node->type == XML_ELEMENT_NODE) {

		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"title")) && cur_node->xmlChildrenNode !=NULL) 
			strcpy(meta.title,(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));

		//it is possible to have more then one author
		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"creator")) && xmlStrcmp(xmlGetProp(cur_node, (const xmlChar *)"role"),(const xmlChar *)"aut")==0 && cur_node->xmlChildrenNode !=NULL) 
		{
			if(strlen(meta.author)==0)
				sprintf(meta.author,"%s",(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));
			
			else
				sprintf(meta.author,"%s, %s",meta.author,(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));
		}

		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"creator")) && xmlStrcmp(xmlGetProp(cur_node, (const xmlChar *)"role"),(const xmlChar *)"trl")==0 && cur_node->xmlChildrenNode !=NULL) 
		{
			if(strlen(meta.translator)==0)
				sprintf(meta.translator,"%s",(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));
			
			else
				sprintf(meta.translator,"%s, %s",meta.translator,(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));
		}

		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"creator")) && xmlStrcmp(xmlGetProp(cur_node, (const xmlChar *)"role"),(const xmlChar *)"ill")==0 && cur_node->xmlChildrenNode !=NULL) 
		{
			if(strlen(meta.illustrator)==0)
				sprintf(meta.illustrator,"%s",(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));
			else
				sprintf(meta.illustrator,"%s, %s",meta.illustrator,(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));
		}

		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"language")) && cur_node->xmlChildrenNode !=NULL) 
			strcpy(meta.language,(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));

		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"publisher")) && cur_node->xmlChildrenNode !=NULL) 
			strcpy(meta.publisher,(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));

		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"rights")) && cur_node->xmlChildrenNode !=NULL) 
			strcpy(meta.rights,(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));

		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"source")) && cur_node->xmlChildrenNode !=NULL) 
			strcpy(meta.source,(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));

		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"description")) && cur_node->xmlChildrenNode !=NULL)
			strcpy(tempbuf,(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));

		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"date")) && cur_node->xmlChildrenNode !=NULL)
		{
			if (strlen((const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1))>4)
			{
				strncpy(meta.date,(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1),4);
				meta.date[4]='\0';
			
			}else 
				strcpy(meta.date,(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));
		}
		
		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"meta")) && xmlStrcmp(xmlGetProp(cur_node, (const xmlChar *)"name"),(const xmlChar *)"amanuensis:generator")==0) 
			strcpy(meta.generator,(const char *)"Amanuensis");

		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"subject")) && cur_node->xmlChildrenNode !=NULL) 
		{
			if(strlen(meta.subject)==0)
				sprintf(meta.subject,"%s",(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));
			else
				sprintf(meta.subject,"%s, %s",meta.subject,(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));
		}
		
		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"meta")) && xmlStrcmp(xmlGetProp(cur_node, (const xmlChar *)"name"),(const xmlChar *)"calibre:series")==0)
			if (xmlGetProp(cur_node, (const xmlChar *)"content")!=NULL)
				strcpy(meta.serie,(const char *)xmlGetProp(cur_node, (const xmlChar *)"content"));
	
		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"meta")) && xmlStrcmp(xmlGetProp(cur_node, (const xmlChar *)"name"),(const xmlChar *)"calibre:series_index")==0)
			if (xmlGetProp(cur_node, (const xmlChar *)"content")!=NULL)
				strcpy(meta.number,(const char *)xmlGetProp(cur_node, (const xmlChar *)"content"));

		if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"identifier")) && xmlStrcmp(xmlGetProp(cur_node, (const xmlChar *)"scheme"),(const xmlChar *)"ISBN")==0 && cur_node->xmlChildrenNode !=NULL) 
			strcpy(meta.isbn,(const char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1));	
		
        }
         parse_xml(cur_node->children, doc);
    }
}


int main (int argc, char **argv)
{

	char * buffer_opf;
	char buf[256];
	int err=0,i;
	int nto;
	int match;
	int size=0;
	struct zip *archive;
	struct zip_file *fpz=NULL;
	struct zip_stat sb;
	regex_t regex;
	const char * srt_regex="\\.opf$";
	const char * html_regex="</body>|</html>|</br>|</div>|</p>|</h1>|</h2>|</h3>|</h4>|</h5>|</h6>|</pre>|</blockquote>|</address>";
	int regerr=0;
	
	//init for message
	OpenScreen();

	if (argc != 2)
	{
		Message(ICON_ERROR,"Fatal error","No epub file input.",7000);
		return 0;
	}
	
	strcpy(ebook,argv[1]);
	
	//open the epub as a zip file
	archive=zip_open(argv[1],ZIP_CHECKCONS,&err);
	if(err != 0 || !archive)
	{
		zip_error_to_str(buf, sizeof buf, err, errno);
		Message(ICON_ERROR,"Fatal error","Unable to open epub file.",7000);
		return 0;
	}
	//number of file in the epub
	nto = zip_get_num_files(archive);

	for (i=0;i<nto;i++)
	{
		zip_stat_index(archive, i, 0, &sb);
		/* Compile regular expression */
		regerr=regcomp(&regex,srt_regex,REG_ICASE|REG_EXTENDED|REG_NOSUB);
		if (regerr)
		{
			Message(ICON_ERROR,"Fatal error","Could not compile regular expression.",7000);
			return(0); 
		}
		
		match = regexec(&regex,sb.name, 0, NULL, 0);
		regfree (&regex);
	
	//ok we found the opf file with the epub metadata
	if (match==0)
	{
		//we need to know the size of the file
		if(zip_stat(archive, sb.name, 0, &sb) == -1)
		{
			Message(ICON_ERROR,"Fatal error","Error when list file in epub.",7000);
			zip_fclose(fpz);
			zip_close(archive);
			return 0;
		}
		//open opf
		fpz=zip_fopen(archive,sb.name,ZIP_FL_UNCHANGED);
		if(!fpz)
		{
			strcpy(buf,zip_strerror(archive));
			Message(ICON_ERROR,"Fatal error","Error opening file in epub.",7000);
			zip_close(archive);
		return 0;
		}
		buffer_opf=malloc(sb.size*sizeof(char)+1);
		if (buffer_opf==NULL)
		{
			Message(ICON_ERROR,"Fatal error","Memory allocation error.",7000);
			zip_fclose(fpz);
			zip_close(archive);
		return 0;
		}
		//reading file
		if(zip_fread(fpz,buffer_opf,sb.size) != sb.size)
		{
			Message(ICON_ERROR,"Fatal error","Error reading file in epub.",7000);
			free(buffer_opf);
			zip_fclose(fpz);
			zip_close(archive);
			return 0;
		}
		size=sb.size;
		zip_fclose(fpz);
		break;
	}
	}

	if (size == 0)
	{
		Message(ICON_ERROR,"Fatal error","opf file not found in epub.",7000);
		return 0;
	}
	
	//end of reading epub file
	zip_close(archive); 
	//now buffer_opf contains the opf file
	//we can parse xml
	
	xmlDoc *doc = NULL;
	xmlNode *root_element = NULL;
	doc = xmlReadMemory(buffer_opf, size, "noname.xml", NULL, 0);
	if (doc == NULL) 
	{
		Message(ICON_ERROR,"Fatal error","Failed to parse file in epub.",7000);
		return 0;
	}
	else
	{
		root_element = xmlDocGetRootElement(doc);
		parse_xml(root_element,doc);
		xmlFreeDoc(doc);
	}

	//cleaning
	xmlCleanupParser();
	free(buffer_opf);

	//now tempbuf contains the description
	//we need to parse decription it can be in html

	if(strlen(tempbuf) != 0)
	{
		//need to detect if description text is html or text format
		regerr=regcomp(&regex,html_regex,REG_ICASE|REG_EXTENDED|REG_NOSUB);
		if (regerr)
		{
			Message(ICON_ERROR,"Fatal error","Could not compile regular expression.",7000);
			return(0); 
		}
	
		match = regexec(&regex,tempbuf, 0, NULL, 0);
		regfree (&regex);
	
		//html format
		if (match==0)
		{
			str_replace(tempbuf,'\n',' ');
			compress_spaces(tempbuf);
		}
		sprintf(tempbuf,"%s",replace_str(tempbuf,"<br>","\n"));
		
		//nothing done for text format
		doc = htmlReadMemory(tempbuf, strlen(tempbuf), "www.description.html", NULL, HTML_PARSE_NOERROR|HTML_PARSE_NOWARNING|HTML_PARSE_NOBLANKS|HTML_PARSE_NOIMPLIED);
	
		if (doc == NULL) 
		{
			Message(ICON_ERROR,"Fatal error","Failed to parse description.",7000);
			return 0;
		}
		else
		{
			root_element = xmlDocGetRootElement(doc);
			parcours_postfixe(root_element, afficher_noeud);
			xmlFreeDoc(doc);
		}
	}
	
	xmlCleanupParser();
	
	//meta.description should be OK now

	cover=GetBookCover(argv[1],150,200);
	//if it fail we use a default image
	if (cover==NULL)
		cover=&no_cover;

	//get epub application
	iv_filetype * ftype=FileType(argv[1]);
	
	//fucking C ! where is my Perl ?
	if (strlen(ftype->program)!=0)
	{
		char * ptr=ftype->program;
		int vpos=0;
		appcount=0;
		int count=0;
		char epubinfo[20];
		while(count<strlen(ftype->program))
		{
			vpos=strcspn(ptr,",");
			strncpy(epubinfo,ptr,vpos);
			epubinfo[vpos]='\0';
//			strncpy(apptab[appcount],ptr,vpos);
//			apptab[appcount][vpos]='\0';
			if (strcmp(epubinfo,"epubinfo.app")!=0)
			{
				strcpy(apptab[appcount],epubinfo);
				appcount++;
			}
			ptr=ptr+vpos+1;	
			count=count+vpos+1;
		}
	}
	
	InkViewMain(keys_handler);
	
	return 0;
}
