#ifndef CODE_HTMLGADGET_CXX
#define CODE_HTMLGADGET_CXX

/*-----------------------------------------------------------------------
 * Xclasses code file
 * ($Id: html_gadget.cxx,v 1.19 1999/02/01 19:45:40 schmitzj Exp $)
 * 
 * Copyright (C) 1998 Jürgen Schmitz
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 *-----------------------------------------------------------------------
 */

#include "types.h"
#include <Xclasses/gadget.h>
#include <Xclasses/html_gadget.h>
#include "include/html_parser.h"
#include "include/html_drawspec.h"
#include "include/html_box.h"
#include "include/html_gadget_p.h"
#include "include/html_drawspec.h"

html_gadget::html_gadget(void) : gadget(), Ddraw(this)
{
	while (!(p=new phtml_gadget))
	{
		outOfMemory("html_gadget");
	}
	p->o=this;
	Name("html_gadget");
	p->horiz.ParentClass(this); p->horiz.Name("hscroller");
	p->vert.ParentClass(this); p->vert.Name("vscroller");
	KeyBorder();
	BorderSize(2);
}
html_gadget::~html_gadget()
{
	if (win) Free();
	delete p;
}

phtml_gadget::phtml_gadget(void) : callable(), horiz(), vert()
{
	parser=NULL;
	xc=NULL;
	gg=NULL;
	vscrollersize=20;
	hscrollersize=18;
	horiz.specialflags|=SPF_NOKEYBORDER;
	vert.specialflags|=SPF_NOKEYBORDER;

	minrows=5;
	mincols=5;
}
phtml_gadget::~phtml_gadget()
{
	delete gg;
	gg=NULL;
	delete xc;
	xc=NULL;
	delete parser;
	parser=NULL;
}

void html_gadget::GSetLimits(void)
{
	minwidth=p->vscrollersize+RealSize()*2+2+p->mincols*textlength(this,"MO")/2;
	minheight=(gg_font()->ascent+gg_font()->descent+2)*p->minrows+RealSize()*2+2+p->hscrollersize;
	setlimit=1;
}
void html_gadget::GExpose(XEvent *event)
{
	if (wasfor)
	{
		wasfor->GExpose(event);
	}
	else
	{
		borderDown(this,0,0,width-p->vscrollersize,height-p->hscrollersize);
 		if (active & GA_KEY)
 		{
 			bordermark(this,0,0,width-p->vscrollersize,height-p->hscrollersize);
 		}
 	    else
     	{
 			borderunmark(this,0,0,width-p->vscrollersize,height-p->hscrollersize);
 	    }
	}
}
void html_gadget::GActionPress(int mx,int my,int rx,int ry,unsigned int state,int button,int reason)
{
	if (reason==GB_KEY)
	{
		bordermark(this,0,0,width-p->vscrollersize,height-p->hscrollersize);
	}
	else if (wasfor)
	{
		wasfor->GActionPress(mx,my,rx,ry,state,button,reason);
	}
}
void html_gadget::GActionRelease(int mx,int my,int rx,int ry,unsigned int state,int button,int reason)
{
	if (reason==GB_KEY)
	{
		borderunmark(this,0,0,width-p->vscrollersize,height-p->hscrollersize);
	}
	else if (wasfor)
	{
		wasfor->GActionRelease(mx,my,rx,ry,state,button,reason);
	}
}
int html_gadget::GActivate(XEvent *event,int why)
{
	if (why==GA_KEY)
	{
		int c;
		char taste[5];
		KeySym key;

		c=XLookupString((XKeyEvent*)event,taste,sizeof(taste),&key,0);
		switch (key)
		{
			case XK_Left:
				p->horiz.Position(p->horiz.Position()-10);
				p->move();
				return GAR_ACTIVE;
				break;
			case XK_Up:
				p->vert.Position(p->vert.Position()-10);
				p->move();
				return GAR_ACTIVE;
				break;
			case XK_Right:
				p->horiz.Position(p->horiz.Position()+10);
				p->move();
				return GAR_ACTIVE;
				break;
			case XK_Down:
				p->vert.Position(p->vert.Position()+10);
				p->move();
				return GAR_ACTIVE;
				break;
			case XK_Page_Up:
				if (p->gg && p->gg->gg_win())
					p->vert.Position(p->vert.Position()-p->gg->gg_height()/2);
				p->move();
				return GAR_ACTIVE;
				break;
			case XK_Page_Down:
				if (p->gg && p->gg->gg_win())
					p->vert.Position(p->vert.Position()+p->gg->gg_height()/2);
				p->move();
				return GAR_ACTIVE;
				break;
			case XK_Home:
				p->vert.Position(0);
				p->horiz.Position(0);
				p->move();
				return GAR_ACTIVE;
				break;
			case XK_End:
				p->vert.Position(p->real_height);
				p->horiz.Position(0);
				p->move();
				return GAR_ACTIVE;
				break;
			default:
				c=DefaultKeyHandler(event);
				break;
		}
		return 0;
	}
	if (wasfor)
	{
		return wasfor->GActivate(event,why);
	}
	ActivateKey();
	return 0;
}
int html_gadget::GSelected(XEvent *event,int why,int wasabove)
{
	if (why==GA_KEY) return GSR_SELECTION;
	if (wasfor)
	{
		if (wasfor==&p->horiz)
		{
			if (wasfor->GSelected(event,why,wasabove) & GSR_SELECTION)
			{
				p->move();
			}
			return 0;
		}
		if (wasfor==&p->vert)
		{
			if (wasfor->GSelected(event,why,wasabove) & GSR_SELECTION)
			{
				p->move();
			}
			return 0;
		} error_printf("How happed this call??\n",this);
		return wasfor->GSelected(event,why,wasabove) & GSR_SELECTION;
	}
	return 0;
}
int html_gadget::GMouseMove(int mx,int my,int rx,int ry,unsigned int state,int button)
{
	if (wasfor)
	{
		if (wasfor==&p->horiz)
		{
			if (wasfor->GMouseMove(mx,my,rx,ry,state,button) & GSR_SELECTION)
			{
				p->move();
			}
			return 0;
		}
		if (wasfor==&p->vert)
		{
			if (wasfor->GMouseMove(mx,my,rx,ry,state,button) & GSR_SELECTION)
			{
				p->move();
			}
			return 0;
		} error_printf("How happed this call??\n",this);
		return wasfor->GMouseMove(mx,my,rx,ry,state,button) & GSR_SELECTION;
	}
	else
	{
		return 0;
	}
}

int html_gadget::Create(void)
{
	Background(col_background());
	if (gadget::Create())
	{
		Mode(GM_KEY|GM_ONEEXPOSE);

		p->horiz.Dimensions(win,0,height-p->hscrollersize,width-p->vscrollersize,p->hscrollersize);
		p->horiz.Arrows();
		p->horiz.ArrowStep(10);
		p->horiz.CopyFont(this);
		p->horiz.Horiz();
		if (!p->horiz.Create())
		{
			gadget::Free();
			return 0;
		}
		p->horiz.SendEventTo(this);

		p->vert.Dimensions(win,width-p->vscrollersize,0,p->hscrollersize,height-p->vscrollersize);
		p->vert.Arrows();
		p->vert.ArrowStep(10);
		p->vert.CopyFont(this);
		p->vert.Vert();
		if (!p->vert.Create())
		{
			p->horiz.Free();
			gadget::Free();
			return 0;
		}
		p->vert.SendEventTo(this);

		p->draw();
		if (p->parser)
		{
			p->parser->Calc(-p->horiz.Position(),-p->vert.Position(),p->gg->gg_width(),p->real_width,p->real_height);
			p->vert.Items(p->real_height);
			p->vert.Visible(p->gg->gg_height());
			p->horiz.Items(p->real_width);
			p->horiz.Visible(p->gg->gg_width());
		}
		return 1;
	}
	return 0;
}
void html_gadget::Free(void)
{
	if (p->parser)
	{
		p->parser->Free();
	}
	if (p->gg && p->gg->gg_win()) p->gg->Free();
	p->vert.Free();
	p->horiz.Free();
	gadget::Free();
}
void html_gadget::Resize(int w,int h)
{
	p->vert.Move(w-p->vscrollersize,0);
	p->vert.Resize(p->vscrollersize,h-p->hscrollersize);
	p->horiz.Move(0,h-p->hscrollersize);
	p->horiz.Resize(w-p->vscrollersize,p->hscrollersize);

	gadget::Resize(w,h);
	if (p->gg)
	{
		p->gg->Resize(w-RealSize()*2-p->vscrollersize-WBORDER*2,h-RealSize()*2-p->hscrollersize-HBORDER*2);
		if (p->parser)
		{
			p->parser->Calc(-p->horiz.Position(),-p->vert.Position(),p->gg->gg_width(),p->real_width,p->real_height);
			p->vert.Items(p->real_height);
			p->vert.Visible(p->gg->gg_height());
			p->horiz.Items(p->real_width);
			p->horiz.Visible(p->gg->gg_width());
			p->parser->Move(-p->horiz.Position(),-p->vert.Position(),p->gg->gg_width(),p->real_width,p->real_height);
		}
	}
}
void html_gadget::Lock(void)
{
	gadget::Lock();
	p->vert.Lock();
	p->horiz.Lock();
}
void html_gadget::Unlock(void)
{
	gadget::Unlock();
	p->vert.Unlock();
	p->horiz.Unlock();
}
void html_gadget::Block(int b)
{
	gadget::Block(b);
	p->vert.Block(b);
	p->horiz.Block(b);
}
void html_gadget::Unblock(int b)
{
	gadget::Unblock(b);
	p->vert.Unblock(b);
	p->horiz.Unblock(b);
}

void html_gadget::MinRows(int m)
{
	p->minrows=m;
}
void html_gadget::MinCols(int m)
{
	p->mincols=m;
}

void html_gadget::Text(char *html)
{
	if (p->parser)
	{
		p->parser->Free();
		delete p->parser;
	}
	p->parser=new html_parser(html);
	if (p->parser)
	{
		p->parser->Callback(p,(void (callable::*)(char *))&phtml_gadget::link);
		if (win)
		{
			p->draw();
			p->parser->Draw(0,0,p->gg->gg_width(),p->real_width,p->real_height);
			p->vert.Position(0);
			p->vert.Items(p->real_height);
			p->vert.Visible(p->gg->gg_height());
			p->horiz.Position(0);
			p->horiz.Items(p->real_width);
			p->horiz.Visible(p->gg->gg_width());
		}
	}
}

void phtml_gadget::move(void)
{
	if (parser && o->win)
	{
		parser->Move(-horiz.Position(),-vert.Position(),gg->gg_width(),real_width,real_height);
	}
}
void phtml_gadget::draw(void)
{
	if (parser)
	{
		if (gg && gg->gg_win()) gg->Free();
		delete xc;
		delete gg;
		gg=new hgadget;
		gg->ParentClass(o);
		gg->Name("html");
		gg->Dimensions(o->win,o->RealSize()+WBORDER,o->RealSize()+HBORDER,o->width-o->RealSize()*2-vscrollersize-WBORDER*2,o->height-o->RealSize()*2-hscrollersize-HBORDER*2);

		xc=new html_drawspecXclasses(gg,this);
		gg->Background(gg->col_background());
		gg->Create();
		parser->Create(xc);
	}
}
void phtml_gadget::link(char *lnk)
{
	printf("clicked hyperlink %s\n",lnk);
}
void phtml_gadget::moveto(int x,int y)
{
	horiz.Position(x);
	vert.Position(y);
	move();
}

hgadget::hgadget(class html_drawspecXclasses *d) : gadget()
{
	Name("hgadget");
	drawspec=d;
	marked=0;
}
hgadget::hgadget(void) : gadget()
{
	Name("hgadget");
	drawspec=NULL;
	marked=0;
}
hgadget::~hgadget()
{
}
int hgadget::Create(void)
{
	if (gadget::Create())
	{
		Mode(GM_ONEEXPOSE|GM_MOUSEMOVE|GM_BUTTON1|GM_MINIMALMOVE|GM_CUTPASTE);
		return 1;
	}
	return 0;
}
void hgadget::GExpose(XEvent *event)
{
	if (drawspec && (!event || (event->type!=NoExpose && event->type!=GraphicsExpose)))
	{
		if (marked)
			drawspec->Unmark();
		marked=0;
		drawspec->Draw();
	}
}
int hgadget::GActivate(XEvent *e,int why)
{
	if (!drawspec) return 0;
	if (why==GM_BUTTON1)
	{
		markx1=e->xbutton.x;
		marky1=e->xbutton.y;
		marked=0;
		drawspec->Unmark();
	}
	return GAR_ACTIVE;
}
int hgadget::GSelected(XEvent *e,int why,int wasabove)
{
	if (why==GM_BUTTON1 && marked)
	{
		char *c=drawspec->Mark(markx1,marky1,markx2,marky2);
		ClipTo(c,strlen(c));
	}
	return wasabove&&!marked?GSR_MESSAGE|GSR_SELECTION:0;
}
int hgadget::GMouseMove(int mx,int my,int rx,int ry,unsigned int state,int button)
{
	if (drawspec)
	{
		if (abs(mx-markx1)>3 || abs(my-marky1)>3)
		{
 			int mv=0;
			int bx=0,by=0,bwidth=0,bheight=0;
			bx=-x;
			by=-y;
			bwidth=width;	// Gesamtbreite - falsch, soll nur sichtbare Breite
			bheight=height;	// Gesamthöhe - falsch, soll nur sichtbare Höhe
 			if (mx<bx)
 			{
 				bx=mx;
 				mv=1;
 			}
 			else if (mx-bx>bwidth)
 			{
 				bx=mx-bwidth;
 				mv=1;
 			}
 			if (my<by)
 			{
 				by=my;
 				mv=1;
 			}
 			else if (my-by>bheight)
 			{
 				by=my-bheight;
 				mv=1;
 			}
 			if (mv)
			{
				if (drawspec->ParentHTMLGadget())
	 				drawspec->ParentHTMLGadget()->moveto(bx,by);
			}

			marked=1;
			markx2=mx;
			marky2=my;
			drawspec->Mark(markx1,marky1,markx2,marky2);
//			ClipTo(c,strlen(c)); 
		}
	}
	return 0;
}
int hgadget::GClipHandler(int why,char *,int)
{
	int r=0;
	if (why==CH_DESELECT)
	{
		if (marked)
		{
			marked=0;
			drawspec->Unmark();
		}
		r=GCH_MESSAGE;
	}
	return r;
}

void hgadget::scroll(int nx,int ny)
{
//	XClearWindow(display(),win);
	XCopyArea(display(),win,win,gc,0,0,width,height,nx-x,ny-y);
}

#endif
