//----------------------------------------------------------------------------
//  Compile intermediates into list of the calc units
//----------------------------------------------------------------------------
#ifdef __BORLANDC__
#include <vcl.h>
#pragma hdrstop
#endif //__BORLANDC__

#include <iostream>
#include <vector>
#include "QCompiler.h"
#include "QCompilerCntl.h"
#include "QParseInfo.h"
#include "QCalcUnit.h"

#include "QC_not.h"
#include "QC_hadamard.h"
#include "QC_cnot.h"
#include "QC_crot.h"
#include "QC_rot.h"
#include "QC_ccnot.h"
#include "QC_pauliX.h"
#include "QC_pauliY.h"
#include "QC_pauliZ.h"
#include "QC_swap.h"
#include "QC_measure.h"

// ---------------------------------------------------------------------------
#ifdef __BORLANDC__
#pragma package(smart_init)
#endif //__BORLANDC__

//----------------------------------------------------------------------------
/**
 *
 */
QCompilerCntl::QCompilerCntl(void) : QCompiler() {
  mNumOfQBits = 0;
  mQParseInfo.clear();
}
//----------------------------------------------------------------------------
/**
 *
 */
QCompilerCntl::QCompilerCntl(std::istream &is) : QCompiler(is) {
  mNumOfQBits = 0;
  mQParseInfo.clear();
}
//----------------------------------------------------------------------------
/**
 *
 */
QCompilerCntl::~QCompilerCntl() {
  mQParseInfo.clear();
}
//----------------------------------------------------------------------------
/**
 *
 */
QCalcUnit *
QCompilerCntl::AllocateControl(const unsigned int index) {
  if (index >= mQParseInfo.size()) {
    return NULL; // Error
  }
  QCalcUnit *cu = NULL;
  const std::vector<int> &targets = mQParseInfo[index].QParseInfo::getTargetIndices();
  switch (mQParseInfo[index].getOperator()) {
  case cn_cnot:
    cu = new QC_cnot(targets[0], targets[1]);
    break;
  case cn_crot:
    cu = new QC_crot(targets[0], targets[1], mQParseInfo[index].getRotation());
    break;
  case cn_rot:
    cu = new QC_rot(targets[0], mQParseInfo[index].getRotation());
    break;
  case cn_h:
    cu = new QC_hadamard(targets[0]);
    break;
  case cn_m:
    cu = new QC_measure(targets[0]);
    break;
  case cn_swap:
    cu = new QC_swap(targets[0], targets[1]);
    break;
  case cn_x:
    cu = new QC_pauliX(targets[0]);
    break;
  case cn_y:
    cu = new QC_pauliY(targets[0]);
    break;
  case cn_z:
    cu = new QC_pauliZ(targets[0]);
    break;
  case cn_not:
    cu = new QC_not(targets[0]);
    break;
  case cn_ccnot:
    cu = new QC_ccnot(targets[0], targets[1], targets[2]);
    break;
  case cn_init:
    mNumOfQBits = targets[0];
  default:
    break;
  }
  return cu;
}
//----------------------------------------------------------------------------
/**
 *
 */
bool
QCompilerCntl::CompileOneLine(const QParseInfo &pinfo) {
  if (!pinfo.getParseResult()) {
    return false;
  }
  mQParseInfo.push_back(pinfo);
  return true;
}
//----------------------------------------------------------------------------
/**
 *
 */
void
QCompilerCntl::CatchError(const QParseInfo &pinfo, const int at) {
#ifdef __BORLANDC__
  //ShowMessage(IntToStr(pinfo.getErrorNo()));
#else
  std::cerr << "Parse error occurred at line " << at << "\n"
            << "Error code = " << pinfo.getErrorNo() << "\n";
#endif //__BORLANDC__
  //TODO:
}
//----------------------------------------------------------------------------
