#include "tk_base.h"
#include "tk_container.h"
#include "tk_scrollbar.h"
#include "tk_place_constraints.h"
#include "tk_toplevel.h"

const Ptr<TkOptionDef> TkBase::OPT_END=0;

TkBase::TkBase(Ptr<TclInterp>& interp)
{
	eventsEnabled=true;

	this->parent=0;
	this->obj=0;
	this->interp=interp;
	this->id=0;
	this->created=false;
	this->displayed=false;
		
	this->name=guid.getId();
	mainWindow=Tk_MainWindow(interp->getInterp());
}

const string& TkBase::getCurrentName() const
{
	string& currentName=*(new string());
	if (parent!=0) currentName.append(parent->getCurrentName());
	currentName.append(".");
	currentName.append(guid.getId());

	return currentName;
}

void TkBase::baseClone(TkBase* obj)
{
	obj->name=name;
	if (!constraints.isNull())
	{
		obj->constraints=constraints->clone();
	}
	if (!tag.isNull())
	{
		obj->tag=tag->clone();
	}
	for(t_option_set::iterator it=optionSet.begin();it!=optionSet.end();it++)
	{
		if (it->first->isSimple())
		{
			obj->setOption(it->first,it->second);
		}
	}
	for(t_option_set::iterator it=bcOptionSet.begin();it!=bcOptionSet.end();it++)
	{
		if (it->first->isSimple())
		{
			obj->setOption(it->first,it->second);
		}
	}
}

Ptr<TXmlObject>& TkBase::getConstraints()
{
	return constraints;
}

void TkBase::setConstraints(Ptr<TXmlObject>& constraints)
{
	this->constraints=constraints;
	invalidate();
}

Ptr<TclInterp>& TkBase::getInterp()
{
	return interp;
}

const TkBase::t_option_set& TkBase::getOptionSet() const
{
	return optionSet;
}

bool TkBase::isCreated() const
{
	return created;
}

Tk_Window TkBase::getWindow() const
{
	return obj;
}

TkContainer* TkBase::getParent()
{
	return parent;
}

Tk_Uid TkBase::getUid() const
{
	return id;
}

const string& TkBase::getName() const
{
	return name;
}


void TkBase::invalidate()
{
	if (displayed&&parent)
		parent->getLayoutManager()->manageLayout(interp,parent,this,constraints);
}

void TkBase::doSerialize(TiXmlElement& element) const
{
	element.SetAttribute("name",name.c_str());

	TiXmlElement optElement("options");
	TiXmlElement cstrElement("constraints");
	TiXmlElement tagElement("tag");

	for(t_option_set::const_iterator it=optionSet.begin();it!=optionSet.end();it++)
	{
		if (!it->first->isSimple()) continue;
		
		TiXmlElement option("option");
		
		option.InsertEndChild(it->first->serialize());
		option.InsertEndChild(it->second->serialize());

		optElement.InsertEndChild(option);
	}

	if (!constraints.isNull())
	{
		cstrElement.InsertEndChild(constraints->serialize());
	}
	if (!tag.isNull())
	{
		tagElement.InsertEndChild(tag->serialize());
	}

	element.InsertEndChild(optElement);
	element.InsertEndChild(cstrElement);
	element.InsertEndChild(tagElement);
}

void TkBase::doDeserialize(const TiXmlElement& element)
{
	name=element.Attribute("name");

	const TiXmlElement& optElement=*element.FirstChildElement("options");
	const TiXmlElement& cstrElement=*element.FirstChildElement("constraints");
	const TiXmlElement& tagElement=*element.FirstChildElement("tag");

	const TiXmlElement* xopt=optElement.FirstChildElement();
	const TiXmlElement* xcstr=cstrElement.FirstChildElement();
	const TiXmlElement* xtag=tagElement.FirstChildElement();

	while(xopt!=0)
	{
		const TiXmlElement* first=xopt->FirstChildElement();
		const TiXmlElement* second=first->NextSiblingElement();

		TkOptionDef* optDef=(TkOptionDef*)TXmlObject::getXmlObject(*first);
		TXmlObject* xmlObject=TXmlObject::getXmlObject(*second);

		setOption(optDef,xmlObject);

		xopt=xopt->NextSiblingElement();
	}
	
	if (xcstr!=0)
	{
		Ptr<TXmlObject> constraints(TXmlObject::getXmlObject(*xcstr));
		setConstraints(constraints);
	}

	if (xtag!=0)
	{
		setTag(TXmlObject::getXmlObject(*xtag));
	}
}

void TkBase::bindEvents()
{
	EActivate::bind(this);
	EButtonPress::bind(this);
	EButtonPress::bind(this);
	EButtonRelease::bind(this);
	ECirculate::bind(this);
	ECirculateRequest::bind(this);
	EColormap::bind(this);
	EConfigure::bind(this);
	EConfigureRequest::bind(this);
	ECreate::bind(this);
	EDeactivate::bind(this);
	EDestroy::bind(this);
	EDouble::bind(this);
	EEnter::bind(this);
	EExpose::bind(this);
	EFocusIn::bind(this);
	EFocusOut::bind(this);
	EGravity::bind(this);
	EKeyPress::bind(this);
	EKeyRelease::bind(this);
	ELeave::bind(this);
	EMap::bind(this);
	EMapRequest::bind(this);
	EMotion::bind(this);
	EMouseWheel::bind(this);
	EProperty::bind(this);
	EReparent::bind(this);
	EResizeRequest::bind(this);
	EUnmap::bind(this);
	EVisibility::bind(this);
}

void TkBase::create()
{
	if (created==false)
	{
		const char* pathName=getCurrentName().c_str();
		/*
		if (uid!=0)
		{
			throw new ExceptionNullPtr();
			return;
			// chyba, tento prvek se jiz pouziva
		}*/
		interp->eval(string(getTkClass())+" "+pathName);
		obj=Tk_NameToWindow(interp->getInterp(),pathName,mainWindow);
		id=Tk_GetUid(pathName);

		created=true;

		//setting options
		for(t_option_set::iterator it=bcOptionSet.begin();it!=bcOptionSet.end();it++)
		{
			setOption(it->first,it->second);
		}
		bcOptionSet.clear();
		
		bindEvents();
	
	}
}

void TkBase::setOption(const Ptr<TkOptionDef>& def,TXmlObject* option)
{
	if (created)
	{
		if (option->hasParent(TkBaseOption::type))
		{
			((TkBaseOption*)option)->setWidget(this);
		}
		optionSet[def]=Ptr<TXmlObject>(option);
		if (def->shouldQuote())
		{
			interp->eval(string(id)+" configure -"+def->getName()+" \""+option->toString()+"\"");
		}
		else
		{
			interp->eval(string(id)+" configure -"+def->getName()+" "+option->toString());
		}
	}
	else
	{
		bcOptionSet[def]=Ptr<TXmlObject>(option);
	}
}

Ptr<TXmlObject>& TkBase::getTag()
{
	return tag;
}

void TkBase::setTag(TXmlObject* tag)
{
	this->tag=tag;
}

Tcl_Obj* TkBase::getOption(const Ptr<TkOptionDef>& def) const
{
	interp->eval(string(id)+" cget -"+def->getName());
	return interp->getObjResult();
}

const string& TkBase::getStrOption(const Ptr<TkOptionDef>& def) const
{
	Tcl_Obj* obj=getOption(def);
	return *(new string(Tcl_GetString(obj)));
}

void TkBase::setRawOption(const string& optionName,const string& value)
{
	interp->eval(string(id)+" configure -"+optionName+" "+value);
}

void TkBase::setName(const string& name)
{
	this->name=name;
}

void TkBase::setEventsEnabled(bool value)
{
	this->eventsEnabled=value;
}

bool TkBase::isEventsEnabled() const
{
	return eventsEnabled;
}

const string& TkBase::toString() const
{	
	if (getUid()==0) return *(new string());
	return *(new string(getUid()));
}

IXScroll::IXScroll():xbar(0)
{
}

void IXScroll::createXBar(Ptr<TclInterp>& interp,TkBase* self,const Ptr<TkOptionDef>& optXScroll)
{
	if (xbar==0) return;
	if (!xbar->isCreated()) xbar->create();

	string xcmd=string("{")+self->getUid()+" xview}";
	xbar->setOption(TkScrollBar::OPT_COMMAND,new TkStringOption(xcmd));

	string mcmd=string("{")+xbar->getUid()+" set}";
	self->setOption(optXScroll,new TkStringOption(mcmd));
}

void IXScroll::setXScrollBar(TkScrollBar* bar)
{
	xbar=bar;
}

IYScroll::IYScroll():ybar(0)
{
}

void IYScroll::createYBar(Ptr<TclInterp>& interp,TkBase* self,const Ptr<TkOptionDef>& optYScroll)
{
	if (ybar==0) return;
	if (!ybar->isCreated()) ybar->create();

	string ycmd=string("{")+self->getUid()+" yview}";
	ybar->setOption(TkScrollBar::OPT_COMMAND,new TkStringOption(ycmd));

	string mcmd=string("{")+ybar->getUid()+" set}";
	self->setOption(optYScroll,new TkStringOption(mcmd));
}

void IYScroll::setYScrollBar(TkScrollBar* bar)
{
	ybar=bar;
}

