package Organisms2.g2;

import Organisms2.Organisms2;
import Organisms2.IFCPlayer;
import Organisms2.IFCConstants;
import Organisms2.Move;
import java.awt.Color;

public class Group2PlayerQ implements IFCPlayer {
	public static final boolean DEBUG = false;
	public static final int NORTH_EAST = 0;
	public static final int NORTH_WEST = 1;
	public static final int SOUTH_EAST = 2;
	public static final int SOUTH_WEST = 3;

	public static final int opposites[] = { _CSTAYPUT, _CEAST, _CWEST, 
		_CSOUTH, _CNORTH 
	};

	private Organisms2 _organisms;
	private Genes _genes;
	private int rounds;
	private int generalDirection;
	private int noGoIndex = 0;

    public void register( Organisms2 organisms, int value ) {
		_organisms = organisms;
		generalDirection = ( int )( Math.random() * 4 );
		rounds = 0;

		if( value == -1 ) {
			_genes = new Genes( -1, Math.min( 1.0 * _organisms.u() / 
				Math.pow( 1.0 * _organisms.v(), 2.0 ), 1.0 ), 0.5 );
		}
		else {
			_genes = new Genes( value );
		}

		if( DEBUG ) {
			System.out.println( _genes.generation() + " " + 
				_genes.foodCultivationProbability() + " " + 
				_genes.moveProbability() + " " + 
				_genes.reproductionThreshold() 
			);
		}
    }

    public Move move( boolean [] foodPresent, int [] enemyPresent, int foodLeft, int energyLeft ) {
		try {
			rounds++;

			/*
			int block_directions = 0;
			int block_index = 0;

			for( int i = 1; i < enemyPresent.length; i++ ) {
				if( enemyPresent[i] == 128 ) {
					block_directions++;
				}
				else {
					block_index = i;
				}
			}

			if( block_directions == 3 ) {
				noGoIndex = opposites[block_index];
				return( new Move( block_index ) );
			}
			*/
			
			// check if food around us; organism should prefer eating from new 
			// food sources
			if( _genes.reproductionThreshold() > 0.5 ) {
				for( int i = 1; i < foodPresent.length; i++ ) {
					//if( foodPresent[i] && ( enemyPresent[i] == -1 ) && i != noGoIndex ) {
					if( foodPresent[i] && ( enemyPresent[i] == -1 ) ) {
						return( new Move( i ) );
					}
				}

				// check if sitting on food
				if( foodLeft > 0 && Math.random() > _genes.foodCultivationProbability() ) {
					return( new Move( _CSTAYPUT ) );
				}

				int available_directions[] = availableDirections( enemyPresent );

				// try to reproduce
				if( energyLeft >= _genes.reproductionThreshold() * _organisms.M() && 
					available_directions.length >= 2 ) {
					// reproduce in direction of food
					for( int i = 1; i < foodPresent.length; i++ ) {
						if( foodPresent[i] && ( enemyPresent[i] == -1 ) ) {
							return( new Move( _CREPRODUCE, i, _genes.mutate() ) );
						}
					}

					// reproduce in a random direction
					return( new Move( _CREPRODUCE, ( int )( Math.random() * 5 ) + 1, 
						_genes.mutate() 
					) );
				}
			}
			else {
				int available_directions[] = availableDirections( enemyPresent );

				// try to reproduce
				if( energyLeft >= _genes.reproductionThreshold() * _organisms.M() && 
					available_directions.length >= 2 ) {
					// reproduce in direction of food
					for( int i = 1; i < foodPresent.length; i++ ) {
						if( foodPresent[i] && ( enemyPresent[i] == -1 ) ) {
							return( new Move( _CREPRODUCE, i, _genes.mutate() ) );
						}
					}

					// reproduce in a random direction
					return( new Move( _CREPRODUCE, ( int )( Math.random() * 5 ) + 1, 
						_genes.mutate() 
					) );
				}

				for( int i = 1; i < foodPresent.length; i++ ) {
					//if( foodPresent[i] && ( enemyPresent[i] == -1 ) && i != noGoIndex ) {
					if( foodPresent[i] && ( enemyPresent[i] == -1 ) ) {
						return( new Move( i ) );
					}
				}

				// check if sitting on food
				if( foodLeft > 0 && Math.random() > _genes.foodCultivationProbability() ) {
					return( new Move( _CSTAYPUT ) );
				}

			}

			int direction = _CSTAYPUT;

			if( Math.random() < _genes.moveProbability() ) {
				switch( generalDirection ) {
					case NORTH_WEST:
						direction = ( Math.random() < 0.5 ? _CNORTH : _CWEST );
						break;
					case NORTH_EAST:
						direction = ( Math.random() < 0.5 ? _CNORTH : _CEAST );
						break;
					case SOUTH_WEST:
						direction = ( Math.random() < 0.5 ? _CSOUTH : _CWEST );
						break;
					case SOUTH_EAST:
						direction = ( Math.random() < 0.5 ? _CSOUTH : _CEAST );
						break;
					default:
						direction = _CSTAYPUT;
				};
			}

			return( new Move( direction ) );
		}
		catch( Exception e ) {
			handleException( e );
		}

		return( null );
    }

	public static int[] availableDirections( int[] enemypresent ) {
		// collect available directions
		int directions[] = new int[5];
		int j = 0;

		// add default
		directions[j++] = _CSTAYPUT;

		for( int i = 1; i < enemypresent.length; i++ ) {
			if( enemypresent[i] == -1 ) {
				directions[j++] = i;
			}
		}

		return( resizeArray( directions, j ) );
	}

	public static int[] resizeArray( int array[], int size ) {
		int new_array[] = new int[size];
		System.arraycopy( array, 0, new_array, 0, size );
		return( new_array );
	}

	public static double[] resizeArray( double array[], int size ) {
		double new_array[] = new double[size];
		System.arraycopy( array, 0, new_array, 0, size );
		return( new_array );
	}

    public int externalState() {
		return( 128 );
    }

    public static void handleException( Exception e ) {
		if( DEBUG ) {
			System.out.println( "Error: " + e.getMessage() );
			e.printStackTrace();
		}
    }

    public String name() {
		return( "Quijibo" );
    }

    public Color color() {
		//return( new Color( ( float )Math.random() , 1.0f, (float)Math.random()));
		return( new Color( 0, 1.0f, 0 ) );
    }

    public boolean interactive() {
		return( false );
	}
}
