///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Copyright (C) 2006 by Intel Corporation and Carnegie Mellon University    //
// Contacts: casey.j.helfrich @ intel.com                                    //
//           bdr @ cs.cmu.edu                                                //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <errno.h>
#include <string.h>

#include "HexRotate.hxx"
#include "CatomWorld.hxx"
#include "CatomSim.hxx"

CODE_MODULE_DECLARATION( HexRotate, HexRotate );

using namespace std;

void HexRotate::newTick() {
  unsigned int i;
  
  if (mode==0) {
    wait=0;
    // less than 2 neighbors, assume 1
    if (hostCatom==10000 || HOSTCATOM.getNthFeature(1)==0) { 
      old_mode = mode = HOSTCATOM.getNthFeature(0);  // mobile
    } else {
      for (i=1; i<=NUM_FEATURES; i++) {
        HOSTCATOMSIM->magnet_state[i] = (i & 0x01)?1:-1;
	//cerr<< "H: " << i << " " << i << " " << ((i&0x01)?1:-1)<<"\n";
      }
      mode=-1; // not mobile
    }
  }
  if (mode>0) {
    bool need_change = false;
    bool is_old_pos = false;
    bool is_detached = ( HOSTCATOM.getNthFeature(0) == 0 );
    for (i=1; i<=NUM_FEATURES; i++) HOSTCATOMSIM->magnet_state[i]=0;
    for (i=0; i<NUM_NEIGHBORS; i++) {
      int k = HOSTCATOM.getNthFeature(i);
      if (k==0) break;
      if ( (k>=mode && k<(mode+(int)NUM_FEATURES/6)) || 
	   k<(mode+(int)NUM_FEATURES/6)-(int)NUM_FEATURES ) need_change=true;
      if ( (k<mode && k>=(mode-(int)NUM_FEATURES/6)) || 
	   k>=(mode-(int)NUM_FEATURES/6)+(int)NUM_FEATURES ) is_old_pos=true;
    }
    Point3D loc = HOSTCATOM.getLocation();
    //cerr << loc.getX() << " " << loc.getY() << " " << loc.getZ() << "  ";
    if (need_change) {
      //cerr << "H " << wait << "\n";
      if (old_mode != mode && wait) {
        wait--;
        HOSTCATOMSIM->magnet_state[mode] = (mode & 0x01)*2-1;
      } else {
        if (old_mode!=mode) {
          old_mode=mode;
          wait=10;
        }
        if (wait) wait--;
        else {
          mode++;
          if (mode==(int)NUM_FEATURES+1) mode = 1;
        }
        HOSTCATOMSIM->magnet_state[mode] = (mode & 0x01)*2-1;
      }
    } else {
      //cerr<<"G "<<wait<<"\n";
      if (is_old_pos && mode!=old_mode) wait++;
      HOSTCATOMSIM->magnet_state[mode] = (mode & 0x01)*2-1;
      if ( is_detached )
        HOSTCATOMSIM->magnet_state[old_mode] = (old_mode & 0x01)*2-1;
    }
  }
}

void HexRotate::endTick() {
}

void HexRotate::oracle() {
  //cout << "HexRotate Oracle: running concurrently with simulationStart\n";
  oracleYield();
  //cout << "HexRotate Oracle: running with other oracles only\n";
  oracleYield();
  while (1) {
    //cout << "HexRotate Oracle: running concurrently with newTick, endTick\n";
    oracleYield();
    //cout << "HexRotate Oracle: running with other oracles only\n";
    oracleYield();
  }
}
