/***************************************************************************
                          Square.cpp  -  description
                             -------------------
    begin                : Tue May 22 2001
    copyright            : (C) 2001 by Sven Reichard
    email                : reichard@math.udel.edu
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
# include "Square.h"
# include "Directions/Direction.h"

# include <iostream>
# include <stdexcept>
# include <sstream>
# include <cassert>
using namespace Alice;
BasicBoard<BasicBoard<const Direction*> >
Square::directionCache;

Square::Square(signed char file, signed char rank):
  mNumber((file<<fileShift) + rank)
{
  mIsValid = true;
  mIsValid &= file >= 0;
  mIsValid &= file < 8;
  mIsValid &= rank >= 0;
  mIsValid &= rank < 8;
};
bool
Square::isValid() const
{
  return mIsValid;
};

Square
Square::left() const
{
  if (! isValid())
    return invalid();
  return Square(file()-1, rank());
};
Square
Square::right() const
{
  if (! isValid())
    return invalid();
  return Square(file() + 1, rank());
};

Square
Square::up() const
{
  if (! isValid())
    return invalid();
  return Square(file(), rank()+1);
};

Square
Square::down() const
{
  if (! isValid())
    return invalid();
  return Square(file(), rank()-1);
};

void
Square::printOn(std::ostream& out) const
{
  out<<("abcdefgh"[file()])<<("12345678"[rank()]);
};

const Direction&
Square::directionTo(const Square& sq) const
{
  if (directionCache[*this][sq] == 0)
    directionCache[*this][sq] = &calculateDirectionTo(sq);
  return *directionCache[*this][sq];
};

const Direction&
Square::calculateDirectionTo(const Square& sq) const
{
  signed char fileDifference(sq.file()-file());
  signed char rankDifference(sq.rank()-rank());
  if (fileDifference == 0) {
    if (rankDifference == 0)
      return Direction::null();
    if (rankDifference > 0)
      return Direction::up();
    return Direction::down();
  }
  if (rankDifference == 0) {
    if (fileDifference > 0)
      return Direction::right();
    return Direction::left();
  }
  if (rankDifference == fileDifference) {
    if (rankDifference > 0)
      return Direction::upRight();
    return Direction::downLeft();
  }
  if (rankDifference == -fileDifference) {
    if (rankDifference > 0)
      return Direction::upLeft();
    return Direction::downRight();
  }
  switch(rankDifference) {
  case 2:
    switch(fileDifference) {
    case 1: return  Direction::upUpRight();
    case -1: return  Direction::upUpLeft();
    }
    break;
  case 1:
    switch(fileDifference) {
    case 2: return  Direction::upRightRight();
    case -2: return  Direction::upLeftLeft();
    }
    break;
  case -1:
    switch(fileDifference) {
    case 2: return  Direction::downRightRight();
    case -2: return  Direction::downLeftLeft();
    }
    break;
  case -2:
    switch(fileDifference) {
    case 1: return  Direction::downDownRight();
    case -1: return  Direction::downDownLeft();
    }
    break;
  }
  return  Direction::null();
};



char
Square::flippedNumber() const
{
  Square flipped(rank(), file());
  return flipped.number();
};

char
Square::getDownDiagonalNumber() const
{
  return rank() + file();
};

char
Square::getUpDiagonalNumber() const
{
  return 8 + rank() - file();
};

std::vector<Square> 
Square::_allInstances(64);

void
Square::initializeAllInstances()
{
  int k = 0;
  for (int i = 0; i < 8; i++)
    for (int j = 0; j < 8; j++, k++)
      _allInstances[k] = Square(i,j);
};

char
Square::getNumberRotated45() const
{
  char result = getDownDiagonalNumber() & 7;
  result <<= 3;
  result += rank();
  return result;
};

char
Square::getNumberRotated135() const
{
  char byte = getUpDiagonalNumber() & 7;
  
  return (byte<<3) + rank();
};

Square::ClassInitializer
Square::_classInit;
