//---------------------------------------------------------------------------
// Toffoli Gate
//---------------------------------------------------------------------------
#include <stdlib.h>
#include "QCCnot.h"
#include "StrUtils.h"
//---------------------------------------------------------------------------
QCCNot::QCCNot(int x,int y) :QCircuit(x,y) {
  Name = GetTypeStr();
  Target1 = Y;
  Target2 = Y;
}
//---------------------------------------------------------------------------
QCCNot::QCCNot(int x,int y, string param) :QCircuit(x,y) {
  Name = GetTypeStr();
  Target1 = Y;
  Target2 = Y;
  vector<string> v = StrUtils::split_str(param);
  Target1 = atoi(v[0].c_str());
  Target2 = atoi(v[1].c_str());
}
//---------------------------------------------------------------------------
void
QCCNot::Draw(QDraw *qDraw) {

  int GridSize = qDraw->GetGridSize();
  int UnitSize = qDraw->GetUnitSize();

  int tx = X;
  int ty = Target1;

  int tx1 = tx*GridSize + GridSize/2;
  int ty1 = ty*GridSize + GridSize/2;
  int tx2 = X*GridSize + GridSize/2;
  int ty2 = Y*GridSize + GridSize/2;
  qDraw->SetPenColor(clBlack);
  qDraw->DrawLine(tx1,ty1,tx2,ty2);
  qDraw->SetBrushColor(clBlack);
  qDraw->Ellipse(tx1-4,ty1-4,tx1+5,ty1+5);

  tx = X;
  ty = Target2;

  tx1 = tx*GridSize + GridSize/2;
  ty1 = ty*GridSize + GridSize/2;
  tx2 = X*GridSize + GridSize/2;
  ty2 = Y*GridSize + GridSize/2;
  qDraw->SetPenColor(clBlack);
  qDraw->DrawLine(tx1,ty1,tx2,ty2);
  qDraw->SetBrushColor(clBlack);
  qDraw->Ellipse(tx1-4,ty1-4,tx1+5,ty1+5);

  int d = (GridSize-UnitSize)/2;
  int x1 = X * GridSize+d;
  int y1 = Y * GridSize+d;
  int x2 = x1 + UnitSize;
  int y2 = y1 + UnitSize;

  qDraw->SetBrushColor(clWhite);
  qDraw->FillRect(x1,y1,x2,y2);
  qDraw->SetPenColor(clBlack);
  qDraw->SetBrushColor(clWhite);
  qDraw->Ellipse(x1,y1,x2,y2);
  qDraw->DrawLine(x1+UnitSize/2,y1,x1+UnitSize/2,y2);
  qDraw->DrawLine(x1,y1+UnitSize/2,x2,y1+UnitSize/2);
}
//---------------------------------------------------------------------------
string
QCCNot::GetCalcText(void) {
  ostringstream os;
  os << "CCNOT(";
  os << "q[" << Y       << "],";
  os << "q[" << Target1 << "],";
  os << "q[" << Target2 << "])";
  return os.str();
}
//---------------------------------------------------------------------------
void
QCCNot::DrawPS(QPSDraw *psDraw) {

  int GridSize = psDraw->GetGridSize();
  int UnitSize = psDraw->GetUnitSize();

  int tx = X;
  int ty = Target1;

  int tx1 = tx*GridSize + GridSize/2;
  int ty1 = ty*GridSize + GridSize/2;
  int tx2 = X*GridSize + GridSize/2;
  int ty2 = Y*GridSize + GridSize/2;
  psDraw->DrawLine(tx1,ty1,tx2,ty2);
  psDraw->DrawFillCircle(tx1,ty1,4);

  tx = X;
  ty = Target2;

  tx1 = tx*GridSize + GridSize/2;
  ty1 = ty*GridSize + GridSize/2;
  tx2 = X*GridSize + GridSize/2;
  ty2 = Y*GridSize + GridSize/2;
  psDraw->DrawLine(tx1,ty1,tx2,ty2);
  psDraw->DrawFillCircle(tx1,ty1,4);

  int d = (GridSize-UnitSize)/2;
  int x1 = X * GridSize+d;
  int y1 = Y * GridSize+d;
  int x2 = x1 + UnitSize;
  int y2 = y1 + UnitSize;

  psDraw->FillRect(x1,y1,x2,y2);
  psDraw->DrawCircle(X*GridSize + GridSize/2,Y*GridSize + GridSize/2,UnitSize/2);
  psDraw->DrawLine(x1+UnitSize/2,y1,x1+UnitSize/2,y2);
  psDraw->DrawLine(x1,y1+UnitSize/2,x2,y1+UnitSize/2);
}
//---------------------------------------------------------------------------
string
QCCNot::GetParam(void) {
  ostringstream os;
  os << Target1 << "," << Target2;
  return os.str();
}
//---------------------------------------------------------------------------
void
QCCNot::Reverse(int y) {
  Y = y - Y;
  Target1 = y - Target1;
  Target2 = y - Target2;
}
//---------------------------------------------------------------------------
TRect QCCNot::GetOccupiedRect() {
  TRect rc;
  rc.left = this->X;
  rc.right = this->X + 1;
  rc.top = this->Y;
  rc.bottom = this->Y + 1;
  if (this->Target1 < this->Y) {
    rc.top = this->Target1;
  } else {
    rc.bottom = this->Target1 + 1;
  }

  if (this->Target2 < rc.top) {
    rc.top = this->Target2;
  } else if (this->Target2 >= rc.bottom) {
    rc.bottom = this->Target2 + 1;
  }
  return rc;
}
//--------------------------------------------------------------------------
QCircuit *QCCNot::Clone() {
  QCCNot * qc = new QCCNot(X, Y);
  qc->SetTarget1(GetTarget1());
  qc->SetTarget2(GetTarget2());
  return (QCircuit*)qc;
}
//---------------------------------------------------------------------------
