#include "onedraft.h"

void onedraft::clear ( void ) {
  for (int lcv1=0;lcv1<MAX;lcv1++)
  for (int lcv2=0;lcv2<MAX;lcv2++) {
    data[lcv1][lcv2][0]=0;
    data[lcv1][lcv2][1]=0;
  }
}

onedraft::onedraft ( ) {
  this->clear();
}

onedraft::onedraft ( const onedraft & x ) {
  for (int lcv1=0;lcv1<MAX;lcv1++)
  for (int lcv2=0;lcv2<MAX;lcv2++) {
    this->data[lcv1][lcv2][0]=x.data[lcv1][lcv2][0];
    this->data[lcv1][lcv2][1]=x.data[lcv1][lcv2][1];
  }
}

onedraft::~onedraft ( ) {
  // nothing to free up
}

onedraft & onedraft::operator = ( const onedraft & x ) {
  for (int lcv1=0;lcv1<MAX;lcv1++)
  for (int lcv2=0;lcv2<MAX;lcv2++) {
    this->data[lcv1][lcv2][0]=x.data[lcv1][lcv2][0];
    this->data[lcv1][lcv2][1]=x.data[lcv1][lcv2][1];
  }
  return *this;
}

void onedraft::dub (void) {
  int toprow;
  int smallmax = MAX/2-1;
  onedraft old;

  old = *this;

    this->clear();
    for (int lcv1=smallmax;lcv1>=0;lcv1--)
    for (int lcv2=smallmax;lcv2>=0;lcv2--) 
    for (int lcv3=0;lcv3<2;lcv3++) {
      int dst=old.data[lcv1][lcv2][lcv3];
      switch (dst) {
        case 0: case 11:
          this->data[lcv1*2][lcv2*2][lcv3] = dst;
          this->data[lcv1*2+1-lcv3][lcv2*2+lcv3][0] = dst;
          this->data[lcv1*2+1-lcv3][lcv2*2+lcv3][1] = dst;
          this->data[lcv1*2+1][lcv2*2+1][lcv3] = dst;
        break;
        case 1: 
          this->data[lcv1*2+lcv3][lcv2*2+lcv3][lcv3] = 0;
          this->data[lcv1*2+1-lcv3][lcv2*2+1-lcv3][lcv3] = 11;
        case 10:
          this->data[lcv1*2+lcv3][lcv2*2+lcv3][lcv3] = 11;
          this->data[lcv1*2+1-lcv3][lcv2*2+lcv3][lcv3] = dst;
          this->data[lcv1*2+1-lcv3][lcv2*2+lcv3][1-lcv3] = 11-dst;
          this->data[lcv1*2+1-lcv3][lcv2*2+1-lcv3][lcv3] = 0;
        break;
        case 4: 
          this->data[lcv1*2+lcv3][lcv2*2+lcv3][lcv3] = (1-lcv3)*11;
          this->data[lcv1*2+1-lcv3][lcv2*2+lcv3][lcv3] = lcv3*11;
        case 7: 
          this->data[lcv1*2+lcv3][lcv2*2+lcv3][lcv3] = lcv3*11;
          this->data[lcv1*2+1-lcv3][lcv2*2+lcv3][lcv3] = (1-lcv3)*11;
          this->data[lcv1*2+1-lcv3][lcv2*2+lcv3][1-lcv3] = dst;
          this->data[lcv1*2+1-lcv3][lcv2*2+1-lcv3][lcv3] = dst;
        break;
        case 5:
          this->data[lcv1*2+1-lcv3][lcv2*2+lcv3][lcv3] = (1-lcv3)*11;
          this->data[lcv1*2+1-lcv3][lcv2*2+1-lcv3][lcv3] = lcv3*11;
        case 6:
          this->data[lcv1*2+lcv3][lcv2*2+lcv3][lcv3] = dst;
          this->data[lcv1*2+1-lcv3][lcv2*2+lcv3][lcv3] = lcv3*11;
          this->data[lcv1*2+1-lcv3][lcv2*2+lcv3][1-lcv3] = dst;
          this->data[lcv1*2+1-lcv3][lcv2*2+1-lcv3][lcv3] = (1-lcv3)*11;
        break;
      }
    }
}

onedraft & onedraft::operator << ( int amt ) {
  int toprow;
  onedraft old;

  old = *this;
  assert(amt>=0);
  assert(amt<6);

  for (int turns=0;turns<amt;turns++) {
    // first, find the top row
    toprow=0;
    for (int lcv1=0;lcv1<MAX;lcv1++)
    for (int lcv2=0;lcv2<MAX;lcv2++) 
    for (int lcv3=0;lcv3<2;lcv3++) {
      if (old.data[lcv1][lcv2][lcv3]!=0
        && toprow < lcv2-lcv1+lcv3) 
           toprow = lcv2-lcv1+lcv3;
    }
    this->clear();
    for (int lcv1=0;lcv1<MAX;lcv1++)
    for (int lcv2=0;lcv2<MAX;lcv2++) 
    for (int lcv3=0;lcv3<2;lcv3++) {
      int dst;
      switch (old.data[lcv1][lcv2][lcv3]) {
        case 0: dst = 0 ; break;
        case 1: dst = (lcv3==0) ? 6 : 5 ; break;
        case 4: dst = (lcv3==0) ? 1 : 10 ; break;
        case 5: dst = 7 ; break;
        case 6: dst = 4 ; break;
        case 7: dst = (lcv3==0) ? 10 : 1 ; break;
        case 10: dst = (lcv3==0) ? 5 : 6 ; break;
        case 11: dst = 11 ; break;
      }
      this->data[toprow-lcv2+lcv1-lcv3][lcv1][1-lcv3] = dst;
    }
  }
  return *this;
}

onedraft & onedraft::operator >> ( int amt ) {
  assert(amt>=0);
  assert(amt<6);
  if (amt != 0) (*this << (6-amt));
  return *this;
}

onedraft & onedraft::operator ! (void) {
  onedraft old;

  old = *this;

  this->clear();
  for (int lcv1=0;lcv1<MAX;lcv1++)
  for (int lcv2=0;lcv2<MAX;lcv2++) 
  for (int lcv3=0;lcv3<2;lcv3++) {
    int dst;
    switch (old.data[lcv1][lcv2][lcv3]) {
      case 0: dst = 0 ; break;
      case 1: dst = 10 ; break;
      case 4: dst = 5 ; break;
      case 5: dst = 4 ; break;
      case 6: dst = 7 ; break;
      case 7: dst = 6 ; break;
      case 10: dst = 1 ; break;
      case 11: dst = 11 ; break;
    }
    this->data[lcv2][lcv1][1-lcv3] = dst;
  }
  return *this;
}

istream & operator >> ( istream & in ,       onedraft & x) {
  int insanityx = 0;
  int insanityq = 0;
  int row=0;int col=0;
  in >> ws;
  while (in.peek() != 'Q') {
    insanityq++;
    in >> ws;
    while (in.peek() != 'X') {
      insanityx++;
      in >> x.data[row][col][0] >> x.data[row][col][1];
      col++;
      in >> ws;
      assert(insanityx<65000);
    }
    insanityx=0;
    in.get();
    in >> ws;
    row++;
    col=0;
    assert(insanityq<65000);
  }
  in.get();
}

ostream & operator << ( ostream & out, const onedraft & x) {
  int maxrow=0; int maxcol=0;
  for (int lcv=0;lcv<MAX;lcv++) for (int lcv2=0;lcv2<MAX;lcv2++)  
    if (x.data[lcv][lcv2][0] != 0 || x.data[lcv][lcv2][1] != 0) maxrow=lcv+1;
  for (int lcv=0;lcv<maxrow;lcv++) { 
    for (int lcv2=0;lcv2<MAX;lcv2++)  
      if (x.data[lcv][lcv2][0] != 0 || x.data[lcv][lcv2][1] != 0) maxcol=lcv2+1;
    for (int lcv2=0;lcv2<maxcol;lcv2++) { 
      out << x.data[lcv][lcv2][0] << " " << x.data[lcv][lcv2][1] << " ";
    }
    out << "X\n";
  }
  out << "Q\n";
}

