//
// CString.cpp
//

#include "CString.h"
#include <math>

//
// konstruktor pro seznam hodnot promennych, promennych je lengthB
//
CString::CString(int lengthB)
{
  if (lengthB<1)lengthB=1;
  this->lengthB=lengthB;
  varList=new bool[this->lengthB];
  for(int ii=0; ii<this->lengthB;ii++)varList[ii]=false;
}


//
// kopirujici konstruktor
//
CString::CString(const CString& _cstring)
{
  delete varList;
  lengthB=_cstring.lengthB;
  varList=new bool[this->lengthB];
  for(int ii=0; ii<this->lengthB;ii++)varList[ii]=_cstring.varList[ii];
}


//
// destruktor
//
CString::~CString()
{
  delete varList;
}


//
// pristup k jednotlivym hodnotam promennych
//
bool& CString::operator[](int pos) const
{
 return this->varList[pos];
}


//
// operator prirazeni
//
CString& CString::operator=(const CString& _cstring)
{
  if (&_cstring!=this || _cstring.lengthB!=this->lengthB)
  {
    for(int ii=0; ii<this->lengthB;ii++)varList[ii]=_cstring.varList[ii];
  }
  return *this;
}


//
// operator porovnani
//
bool CString::operator==(const CString& _cstring)
{
  for(int ii=0; ii<this->lengthB;ii++)
  {
    if (varList[ii]!=_cstring.varList[ii]) return false;
  }
  return true;
}


//
// hodnotici funkce, vyber urcitou funkci(podle vyberu uzivatele), jejiz hodnotu pak nasledne vrati
//
//int CString::fitness(InnerForm *inner, int fitnessSelected, int position)
int CString::fitness(InnerForm *inner, int fitnessSelected)
{
  switch(fitnessSelected)
  {
    case 0:{return clausesSat(inner);}
//    case 1:{return improvement(inner, position);}
    case 1:{return weightedSat(inner);}
    default:{return 0;}
  };
}


#ifdef consoleOut
//
// vypise aktualni ohodnoceni promennych
//
ostream& operator<<(ostream &o, const CString & cstr)
{
 for (int ii=0; ii<cstr.lengthB; ii++)
 {
   o << (int)cstr.varList[ii] << " ";
 }
 return o;
}
#endif

//
// vrati pocet klauzuli, ktere jsou v danem ohodnoceni NEsplnene
//
int CString::clausesUnsat(InnerForm *inner)
{
  int unsat, lit, sign;
  bool bad;

  unsat = 0;
  for (int ii=0; ii < inner->numberOfClauses; ii++)
  {
    bad = true;
    for (int jj=1; jj < inner->clauses[ii][0]+1; jj++)
    {
      lit = inner->clauses[ii][jj];
      sign = lit > 0 ? 1 : 0;
      if ( varList[abs(lit)-1] == sign )
      {
        bad = false;
        break;
      }
    }
    if (bad)
    {
      unsat++;
    }
  }
  return unsat;
}


//
// vrati pocet klauzuli, ktere jsou v danem ohodnoceni SPLNENE
//
int CString::clausesSat(InnerForm *inner)
{
  return (inner->numberOfClauses-clausesUnsat(inner));
}


//
// vrati prirustek poctu splnenych klauzuli po invertovani promenne s indexem position
//
int CString::improvement(InnerForm *inner, int position)
{
  int satBefore=0, satAfter=0;

  satBefore=clausesSat(inner);
  varList[position]=1-varList[position]; //preklopeni promenne na danem miste
  satAfter=clausesSat(inner);
  varList[position]=1-varList[position]; //nastaveni promenne na puvodni hodnotu
  return satAfter-satBefore;
}


//
// vrati reprezentaci ve forme textoveho retezce
//
char * CString::toString()
{
  char *ret = new char[lengthB+1];
  for (int ii=0; ii<lengthB; ii++)
  {
    ret[ii]=0x30+varList[ii];
  }
  ret[lengthB]=0x00;
  return ret;
}


//
// takova fitness, ktera vraci jako vystup soucet vah vsech promennych ohodnocenych jednotkou minus penalty*pocet nesplnenych klauzuli
//
int CString::weightedSat(InnerForm *inner)
{
  int retVal=0;
  for(int ii=0; ii<this->lengthB;ii++)retVal+=varList[ii]*inner->weightTable[ii];
  retVal-=clausesUnsat(inner)*inner->unsatPenalty;
  return retVal;
}


#ifdef consoleOut
void InnerForm::print()
{
  for (int ii=0; ii < numberOfClauses; ii++)
  {
   for (int jj=1; jj < clauses[ii][0]+1; jj++)
   {
      cout << clauses[ii][jj] << " ";
   }
   cout << endl;
  }

}
#endif
