#include "grace_tags.h"
#include <cmath>

HtmlComment::HtmlComment()
: conform_string(),
  TagAttribute(false, false, false),
  HtmlField()
{ 
    defineHeadAttribute(*this);
}

HtmlComment::HtmlComment(const string& cmt)
: conform_string(cmt),
  TagAttribute(false, false, false),
  HtmlField()
{ 
    defineHeadAttribute(*this);
}

HtmlComment::HtmlComment(const char*const cmt)
: conform_string(cmt),
  TagAttribute(false, false, false),
  HtmlField()
{ 
    defineHeadAttribute(*this);
}

const string&
HtmlComment::name() const { return nullString; }

const string&
HtmlComment::tagName() const { return TAG_NAME; }

void
HtmlComment::write(ostream& os) const { startTag.write(os); }
    
void
HtmlComment::readSingle(istream& is) { is >> *this; }

void
HtmlComment::writeSingle(ostream& os) const { os << *this; }

const string HtmlComment::TAG_NAME("!");



HtmlSystem::HtmlSystem()
: HtmlField(),
  id(ATTRIB_ID_NAME, string(), true, false),
  sys_name(ATTRIB_SYS_NAME, string(), true, true)
{
	defineHeadAttribute(id);
	defineHeadAttribute(sys_name);
}

HtmlSystem::HtmlSystem(const string& id)
: HtmlField(),
  id(ATTRIB_ID_NAME, id, true, false),
  sys_name(ATTRIB_SYS_NAME, string(), true, true)
{
	defineHeadAttribute(this->id);
	defineHeadAttribute(sys_name);
}

HtmlSystem::HtmlSystem(const string& id, const string& name)
: HtmlField(),
  id(ATTRIB_ID_NAME, id, true, false),
  sys_name(ATTRIB_SYS_NAME, name, true, true)
{
	defineHeadAttribute(this->id);
	defineHeadAttribute(sys_name);
}

const string&
HtmlSystem::tagName() const { return TAG_NAME; }

void
HtmlSystem::write(ostream& os) const { startTag.write(os); }

const string HtmlSystem::TAG_NAME("SYSTEM");
const string HtmlSystem::ATTRIB_ID_NAME("id");
const string HtmlSystem::ATTRIB_SYS_NAME("name");



HtmlCorpus::HtmlCorpus()
: HtmlField(),
  id(ATTRIB_ID_NAME, 0, true, false)
{
	defineHeadAttribute(id);
}

HtmlCorpus::HtmlCorpus(const ShortNatural& id)
: HtmlField(),
  id(ATTRIB_ID_NAME, id, true, false)
{
	defineHeadAttribute(this->id);
}

const string&
HtmlCorpus::tagName() const { return TAG_NAME; }

void
HtmlCorpus::write(ostream& os) const { startTag.write(os); }

const string HtmlCorpus::TAG_NAME("CORPUS");
const string HtmlCorpus::ATTRIB_ID_NAME("id");


HtmlCase::HtmlCase()
: HtmlField(),
  caseNo(ATTRIB_CASE_NAME, 0, true, false)
{
	defineHeadAttribute(caseNo);
}

HtmlCase::HtmlCase(const VeryLongNatural& caseNo)
: HtmlField(),
  caseNo(ATTRIB_CASE_NAME, caseNo, true, false)
{
	defineHeadAttribute(this->caseNo);
}

const string&
HtmlCase::tagName() const  { return TAG_NAME; }

void
HtmlCase::write(ostream& os) const { startTag.write(os); }

const string HtmlCase::TAG_NAME("CASE");
const string HtmlCase::ATTRIB_CASE_NAME("no");



HtmlToken::HtmlToken()
: HtmlField(false),
  pos(ATTRIB_POS_NAME, 0, true, false),
  tag(ATTRIB_TAG_NAME, string(), true, false),
  segOrig(ATTRIB_SEG_NAME, string(), true, true),
  tok()
{
	defineHeadAttribute(pos);
	defineHeadAttribute(tag);
	defineHeadAttribute(segOrig);
}

HtmlToken::HtmlToken(const VeryLongNatural& pos, const string& tag,
	                 const string& sgOrig, const string& token)
: HtmlField(false),
  pos(ATTRIB_POS_NAME, pos, true, false),
  tag(ATTRIB_TAG_NAME, tag, true, false),
  segOrig(ATTRIB_SEG_NAME, sgOrig, true, true),
  tok(token)
{
	defineHeadAttribute(this->pos);
	defineHeadAttribute(this->tag);
	defineHeadAttribute(this->segOrig);
}


const string&
HtmlToken::tagName() const { return TAG_NAME; }

void
HtmlToken::writeField(ostream& os) const { os << tok; }

void
HtmlToken::readField(istream& in) { extendedGet(in,tok,string("<")); }

const string HtmlToken::TAG_NAME("TOK");
const string HtmlToken::ATTRIB_POS_NAME("n");
const string HtmlToken::ATTRIB_TAG_NAME("tag");
const string HtmlToken::ATTRIB_SEG_NAME("segOrig");


HtmlRes::HtmlRes()
: HtmlField(),
  TagAttribute(true, false, false),
  ver(ATTRIB_VER_NAME, 0, true, false),
  res(Ok)
{
	defineHeadAttribute(ver);
	defineHeadAttribute(*this);
}

HtmlRes::HtmlRes(const Natural ver, const SingleRes res)
: HtmlField(),
  TagAttribute(true, false, false),
  ver(ATTRIB_VER_NAME, ver, true, false),
  res(res)
{
	defineHeadAttribute(this->ver);
	defineHeadAttribute(*this);
}

const string&
HtmlRes::name() const { return ATTRIB_RES_NAME; }

const string&
HtmlRes::tagName() const { return TAG_NAME; }

void
HtmlRes::write(ostream& os) const { startTag.write(os); }

void
HtmlRes::writeSingle(ostream& os) const
{
	switch(res)
	{
		case Ok      : os << "OK"; break;
		case NonEval : os << "NEV"; break;
		case Err     : os << "ERR"; break;
		case Sil     : os << "SIL"; break;
	}
}

const string HtmlRes::TAG_NAME("RES");
const string HtmlRes::ATTRIB_VER_NAME("ver");
const string HtmlRes::ATTRIB_RES_NAME("val");


HtmlTranscoded::HtmlTranscoded()
: HtmlField(),
  ver(ATTRIB_VER_NAME, 0, true, false),
  val(ATTRIB_VAL_NAME, string(), true, false)
{
	defineHeadAttribute(ver);
	defineHeadAttribute(val);
}

HtmlTranscoded::HtmlTranscoded(const Natural ver, const string& tag)
: HtmlField(),
  ver(ATTRIB_VER_NAME, ver, true, false),
  val(ATTRIB_VAL_NAME, tag, true, false)
{
	defineHeadAttribute(this->ver);
	defineHeadAttribute(val);
}

const string& 
HtmlTranscoded::tagName() const { return TAG_NAME; }

void 
HtmlTranscoded::write(ostream& os) const { startTag.write(os); }
	
const string HtmlTranscoded::TAG_NAME("TRANSCODED");
const string HtmlTranscoded::ATTRIB_VER_NAME("ver");
const string HtmlTranscoded::ATTRIB_VAL_NAME("val");


HtmlResultats::HtmlResultats()
: HtmlField(),
  evalType(),
  ver(ATTRIBS_NAME[0], 0),
  nbCases(ATTRIBS_NAME[1], 0),
  silences(ATTRIBS_NAME[2], 0),
  oks(ATTRIBS_NAME[3], 0),
  silencesOk(ATTRIBS_NAME[4], 0),
  silencesErr(ATTRIBS_NAME[5], 0),
  errs(ATTRIBS_NAME[6], 0),
  neutralized(ATTRIBS_NAME[7], 0),
  unevaluable(ATTRIBS_NAME[8], 0),
  wrongAlign(ATTRIBS_NAME[9], 0),
  averageSilOk(ATTRIBS_NAME[10], 0.0),
  averageSilErr(ATTRIBS_NAME[11], 0.0),
  ratioUnevaluable(ATTRIBS_NAME[12], 0.0),
  precision(ATTRIBS_NAME[13], 0.0),
  decision(ATTRIBS_NAME[14], 0.0),
  minPrecision(ATTRIBS_NAME[15], 0.0),
  subMinPrecision(ATTRIBS_NAME[16], 0.0),
  averagePrecision(ATTRIBS_NAME[17], 0.0),
  subAveragePrecision(ATTRIBS_NAME[18], 0.0),
  supAveragePrecision(ATTRIBS_NAME[19], 0.0),
  maxPrecision(ATTRIBS_NAME[20], 0.0),
  supMaxPrecision(ATTRIBS_NAME[21], 0.0)
{
	defineHeadAttribute(evalType);
	defineHeadAttribute(ver);
	defineHeadAttribute(nbCases);
	defineHeadAttribute(silences);
	defineHeadAttribute(oks);
	defineHeadAttribute(silencesOk);
	defineHeadAttribute(silencesErr);
	defineHeadAttribute(errs);
	defineHeadAttribute(neutralized);
	defineHeadAttribute(unevaluable);
	defineHeadAttribute(wrongAlign);
	defineHeadAttribute(averageSilOk);
	defineHeadAttribute(averageSilErr);
	defineHeadAttribute(ratioUnevaluable);
	defineHeadAttribute(precision);
	defineHeadAttribute(decision);
	defineHeadAttribute(minPrecision);
	defineHeadAttribute(averagePrecision);
	defineHeadAttribute(maxPrecision);
	defineHeadAttribute(subMinPrecision);
	defineHeadAttribute(subAveragePrecision);
	defineHeadAttribute(supAveragePrecision);
	defineHeadAttribute(supMaxPrecision);
}

void
HtmlResultats::mergeWith(const HtmlResultats& res)
{
	nbCases() += res.nbCases();
	silences() += res.silences();
    oks() += res.oks();
    silencesOk() += res.silencesOk();
    silencesErr() += res.silencesErr();
    errs() += res.errs();
    neutralized() += res.neutralized();
    unevaluable() += res.unevaluable();
    wrongAlign() += res.wrongAlign();
    averageSilOk() += res.averageSilOk();
    averageSilErr() += res.averageSilErr();
}

void
HtmlResultats::computeScore()
{
	Real computed(nbCases() - unevaluable() - neutralized() - wrongAlign());
	ratioUnevaluable() = 100. * (Real)unevaluable() / (Real)(nbCases() - neutralized());
	precision() = ((oks() + errs()) > 0 ? (oks() / (Real)(oks() + errs())) : 0.0);
	if (computed > 0.0)
	{
		decision() = (oks() + errs()) / computed;
		minPrecision() = (oks() + silencesOk()) / computed;
		averagePrecision() = (oks() + averageSilOk()) / computed;
		maxPrecision() = (oks() + (silences() - silencesErr())) / computed;
	}

	// Compute PZone
	const Real z(1.96); // z(0.025) 0.025-fractile de la loi normale centree reduite = 1.96
	const Real denum(nbCases()-unevaluable());
	if (denum > 0.0)
	{
		subMinPrecision() = max((minPrecision()-z*sqrt((minPrecision()*(1.-minPrecision()))/denum)), 0.0);
		subAveragePrecision() = max((averagePrecision()-z*sqrt((averagePrecision()*(1.-averagePrecision()))/denum)), 0.0);
		supAveragePrecision() = min((averagePrecision()+z*sqrt((averagePrecision()*(1.-averagePrecision()))/denum)), 1.0);
		supMaxPrecision() = min((maxPrecision()+z*sqrt((maxPrecision()*(1.-maxPrecision()))/denum)), 1.0);
	}
}

void
HtmlResultats::reset()
{
	evalType() = Directe;
    ver() = 0;
    nbCases() = 0;
    silences() = 0;
    oks() = 0;
    silencesOk() = 0;
    silencesErr() = 0;
    errs() = 0;
    neutralized() = 0;
    unevaluable() = 0;
    wrongAlign() = 0;
    averageSilOk() = 0.0;
    averageSilErr() = 0.0;
    ratioUnevaluable() = 0.0;
    precision() = 0.0;
    decision() = 0.0;
    minPrecision() = 0.0;
    subMinPrecision() = 0.0;
    averagePrecision() = 0.0;
    subAveragePrecision() = 0.0;
    supAveragePrecision() = 0.0;
    maxPrecision() = 0.0;
    supMaxPrecision() = 0.0;
}

const string& 
HtmlResultats::tagName() const { return TAG_NAME; }

void
HtmlResultats::dump(ostream& os) const
{
	os << "# Resultats  (nb cases:" << nbCases() << ")\n"
	   << "# Ntr:" << neutralized() << " - BadAlign:" << wrongAlign() << " - NonEval:" << unevaluable() << '\n'
	   << "# Oks:" << oks() << " (+" << silencesOk() << ")\n"
	   << "# Err:" << errs() << " (+" << silencesErr() << ")\n"
	   << "# Sil:" << silences() << " (PrbOk:" << averageSilOk() << " PrbErr:" << averageSilErr() << ")\n"
	   << "# Score: P = " << precision() << "  / D = " << decision() << '\n'
	   << "# Intrv [min,moy,max]: [" << minPrecision() << ',' << averagePrecision() << ',' << maxPrecision() << "]\n"
	   << "# Intrv [min-,moy-,moy+,max+]: [" << subMinPrecision() << ',' << subAveragePrecision() << ',' 
	                                         << supAveragePrecision() << ',' << supMaxPrecision() << "]\n";
}

const string HtmlResultats::TAG_NAME("RESULT");
const string HtmlResultats::ATTRIBS_NAME[22] = 
{
	string("ver"),
	string("cases"),
	string("silences"),
	string("oks"),
	string("silences_ok"),
	string("silences_err"),
	string("errors"),
	string("neutralized"),
	string("unevaluable"),
	string("wrong_alignment"),
	string("average_sil_ok"),
	string("average_sil_err"),
	string("ratio_unevaluable"),
	string("precision"),
	string("decision"),
	string("min_precision"),
	string("sub_min_precision"),
	string("average_precision"),
	string("sub_average_precision"),
	string("sup_average_precision"),
	string("max_precision"),
	string("sup_max_precision")
};



