package com.medievaltech.advancewars;

import java.io.*;

import com.medievaltech.advancewars.Enum.*;
import com.medievaltech.unit.*;
import com.medievaltech.gui.*;

import android.content.Context;
import android.graphics.*;
import android.os.*;
import android.view.*;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

class GameView extends SurfaceView implements SurfaceHolder.Callback {
	
    class DrawingThread extends Thread {        
        public GameState mGameState;
        
        //maybe make this private and make an accessor for it
        public Map mMap;
        
        public Tile grassTile, oceanTile;
        
        public Turn mTurn;
        
        //temporary variable to let the enemy control a specific unit
        //ownership of units hasn't been implemented yet
        public Unit enemyUnit;
        
        private int mCanvasHeight = 1;
        private int mCanvasWidth = 1;

        private Paint mLinePaint, mTextPaint, mButtonPaint, mTilePaint1,
        			mTilePaint2, mSelectionPaint, mUnitPaint;

        /** Indicate whether the surface has been created & is ready to draw */
        private boolean mRun = false;

        /** Handle to the surface manager object we interact with */
        private SurfaceHolder mSurfaceHolder;
        
        private com.medievaltech.gui.Window wndMainMenu;
        private Unit selectedUnit;
        
        public DrawingThread(SurfaceHolder surfaceHolder, Context context, Handler handler) {
            mSurfaceHolder = surfaceHolder;
            
            mLinePaint = new Paint();
            mLinePaint.setAntiAlias(true);
            mLinePaint.setARGB(255, 0, 255, 0);

            mTextPaint = new Paint();
            mTextPaint.setAntiAlias(true);
            mTextPaint.setARGB(255, 255, 255, 255);
            mTextPaint.setTextSize(12);
            mTextPaint.setTextAlign(Paint.Align.CENTER);
            
            mButtonPaint = new Paint();
            mButtonPaint.setAntiAlias(true);
            mButtonPaint.setARGB(255, 0, 0, 0);
            mButtonPaint.setTextSize(20);
            mButtonPaint.setTextAlign(Paint.Align.CENTER);
            
            mTilePaint1 = new Paint();
            mTilePaint1.setAntiAlias(true);
            mTilePaint1.setARGB(255, 0, 255, 0);
            
            mTilePaint2 = new Paint();
            mTilePaint2.setAntiAlias(true);
            mTilePaint2.setARGB(255, 0, 0, 255);
            
            mUnitPaint = new Paint();
            mUnitPaint.setAntiAlias(true);
            mUnitPaint.setARGB(255, 255, 0, 0);
            
            mSelectionPaint = new Paint();
            mSelectionPaint.setAntiAlias(true);
            mSelectionPaint.setARGB(255, 255, 127, 0);
            
            wndMainMenu = new com.medievaltech.gui.Window(0, 0, 320, 450);;
            wndMainMenu.addGUIObject("txtTitle", new Text("Main Menu", 100, 30, 120, 20, mTextPaint));
            wndMainMenu.addGUIObject("btnNewGame", new Button("New Game", 100, 90, 120, 20, mLinePaint, mButtonPaint));
            wndMainMenu.addGUIObject("btnLoadGame", new Button("Load Game", 100, 125, 120, 20, mLinePaint, mButtonPaint));
            wndMainMenu.addGUIObject("btnMapEditor", new Button("Map Editor", 100, 160, 120, 20, mLinePaint, mButtonPaint));
            wndMainMenu.addGUIObject("btnQuit", new Button("Quit", 100, 195, 120, 20, mLinePaint, mButtonPaint));
            
            grassTile = new Tile(mTilePaint1, TerrainType.LAND);
            oceanTile = new Tile(mTilePaint2, TerrainType.SEA);
            
            mMap = new Map(grassTile, 6, 8, new Point(10, 25));
            
            boolean land = true;
            
            for(int x=0; x<mMap.getWidth(); x++) {
    			for(int y=0; y<mMap.getHeight(); y++) {
    				if(land)
    					mMap.setTile(x, y, new Tile(grassTile, new Point(x, y)));
    				else
    					mMap.setTile(x, y, new Tile(oceanTile, new Point(x, y)));
    				land = !land;
    			}
    			land = !land;
            }
            
            enemyUnit = new Soldier(mUnitPaint);
            
            mMap.getTile(0, 0).addUnit(enemyUnit);
            mMap.getTile(2, 3).addUnit(new Soldier(mUnitPaint));
            mMap.getTile(5, 6).addUnit(new Soldier(mUnitPaint));
            
            mTurn = Turn.YOUR_TURN;
            
            mGameState = GameState.MAIN_MENU;
        }
        
        /**
         * Starts the game, setting parameters for the current difficulty.
         */
        // I don't think this gets called now. maybe we should call it in the thread constructor
        public void doStart() {
            synchronized (mSurfaceHolder) {
                Log.i("AdvanceWars", "Player's turn starting now");
                mGameState = GameState.MAIN_MENU;
            }
        }

        @Override
        public void run() {
            while (mRun) {
                Canvas c = null;
                try {
                    c = mSurfaceHolder.lockCanvas(null);
                    synchronized(mSurfaceHolder) {
                    	doLogic();
                        doDraw(c);
                    }
                } finally {
                    // do this in a finally so that if an exception is thrown
                    // during the above, we don't leave the Surface in an
                    // inconsistent state
                    if (c != null) {
                        mSurfaceHolder.unlockCanvasAndPost(c);
                    }
                }
            }
        }

        /**
         * Used to signal the thread whether it should be running or not.
         * Passing true allows the thread to run; passing false will shut it
         * down if it's already running. Calling start() after this was most
         * recently called with false will result in an immediate shutdown.
         * 
         * @param b true to run, false to shut down
         */
        public void setRunning(boolean b) {
            mRun = b;
        }
        
        public void setGameState(GameState state) {
            synchronized (mSurfaceHolder) {
                mGameState = state;
            }
        }
        
        /* Callback invoked when the surface dimensions change. */
        public void setSurfaceSize(int width, int height) {
            // synchronized to make sure these all change atomically
            synchronized (mSurfaceHolder) {
                mCanvasWidth = width;
                mCanvasHeight = height;
                
                Log.i("AdvanceWars", "width: "+mCanvasWidth+", height: "+mCanvasHeight);
            }
        }
        
        private void doLogic() {
        	if(mTurn == Turn.YOUR_TURN)
        		return;
        	
        	switch(mGameState) {
        	case BATTLE_MAP:
        		int x = thread.enemyUnit.location.x;
        		int y = thread.enemyUnit.location.y;
        		thread.mMap.getTile(x, y).removeUnit();
				thread.mMap.getTile(x, y+1).addUnit(thread.enemyUnit);
        		mTurn = Turn.YOUR_TURN;
        		break;
        	}
        }

        /**
         * Draws the ship, fuel/speed bars, and background to the provided
         * Canvas.
         */
        private void doDraw(Canvas canvas) {
        	canvas.drawColor(Color.BLACK);
        	
        	switch(mGameState) {
        	case MAIN_MENU:
            	wndMainMenu.draw(canvas);
        		break;
        	case BATTLE_MAP:
        		mTextPaint.setTextSize(12);
            	
            	mMap.draw(canvas);
            	
            	if(selectedUnit != null) {
	            	for(Point p : selectedUnit.getMovementRange()) {
	            		canvas.drawRect(p.x*50+10, p.y*50+25, p.x*50+50+10, p.y*50+50+25, mSelectionPaint);
	            	}
            	}
            	
            	mMap.drawUnits(canvas);
            	
        		break;
        	}
        }
    }

    /** Pointer to the text view to display "Paused.." etc. */
    private TextView mStatusText;

    /** The thread that actually draws the animation */
    private DrawingThread thread;
    
    public Game mGame;

    public GameView(Context context, AttributeSet attrs) {
        super(context, attrs);

        // register our interest in hearing about changes to our surface
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);

        // create thread only; it's started in surfaceCreated()
        thread = new DrawingThread(holder, context, new Handler() {
            @Override
            public void handleMessage(Message m) {
                mStatusText.setVisibility(m.getData().getInt("viz"));
                mStatusText.setText(m.getData().getString("text"));
            }
        });

        setFocusable(true); // make sure we get key events
    }

    @Override public boolean onTouchEvent(MotionEvent event) {
    	Log.i("AdvanceWars", "Detected touch event");
    	
    	if(event.getAction() == MotionEvent.ACTION_UP) {
    		Log.i("AdvanceWars", "Detected UP touch action");
    		switch(thread.mGameState) {
    		case MAIN_MENU:
    			Log.i("AdvanceWars", "Switching to battle map");
    			if(thread.wndMainMenu.getGUIObject("btnNewGame").isClicked(event.getX(), event.getY())) {
    				thread.mGameState = GameState.BATTLE_MAP;
    			}else if(thread.wndMainMenu.getGUIObject("btnLoadGame").isClicked(event.getX(), event.getY())) {
    				BufferedReader b;
            		try {
            			b = new BufferedReader(new FileReader(android.os.Environment.getExternalStorageDirectory()+"/save.txt"));
            			
            			int width = Integer.parseInt(b.readLine());
            			int height = Integer.parseInt(b.readLine());
            			
            			String offset = b.readLine();
            			Log.i("GameSave", offset);
            			int offsetX = Integer.parseInt(offset.substring(0, offset.indexOf("x")));
            			int offsetY = Integer.parseInt(offset.substring(offset.indexOf("x")+1));
            			
            			thread.mMap = new Map(thread.grassTile, width, height, new Point(offsetX, offsetY));
            			
            			Log.i("GameSave", "Created the map");
            			
            			for(int x=0; x<width; x++) {
            				String line = b.readLine();
            				Log.i("GameSave", line);
            				String[] arr = line.split(",");
            				for(int y=0; y<arr.length; y++) {
            					TerrainType type = TerrainType.values()[Integer.parseInt(arr[y])];
            					if(type.equals(TerrainType.LAND))
                					thread.mMap.setTile(x, y, new Tile(thread.grassTile, new Point(10, 25)));
                				else
                					thread.mMap.setTile(x, y, new Tile(thread.oceanTile, new Point(10, 25)));
            				}
            			}
            			
            			while(b.ready()) {
            				String unit = b.readLine();
            				Log.i("GameSave", unit);
            				int x = Integer.parseInt(unit.substring(0, unit.indexOf(",")));
                			int y = Integer.parseInt(unit.substring(unit.indexOf(",")+1));
            				
            				mGame.mThread.mMap.getTile(x, y).addUnit(new Soldier(mGame.mThread.mUnitPaint));
            			}
            			
            			b.close();
            		}catch(IOException ioe) {
            			ioe.printStackTrace();
            		}
    				thread.mGameState = GameState.BATTLE_MAP;
    			}else if(thread.wndMainMenu.getGUIObject("btnQuit").isClicked(event.getX(), event.getY())) {
    				mGame.finish();
    			}
    			break;
    		case BATTLE_MAP:
    			Log.i("AdvanceWars", "Touch event detected on battle map");
    			
    			if(event.getX() >= thread.mMap.offset.x && event.getY() >= thread.mMap.offset.y) {
    				int x = ((int)event.getX() - thread.mMap.offset.x) / 50;
    				int y = ((int)event.getY() - thread.mMap.offset.y) / 50;
    				
    				Unit target = thread.mMap.getTile(x, y).currentUnit;
    				
    				if(thread.selectedUnit != null && thread.selectedUnit.getMovementRange().contains(new Point(x, y))) {
    					if(target == null || target == thread.selectedUnit) {
	    						thread.mMap.getTile(thread.selectedUnit.location.x, thread.selectedUnit.location.y).removeUnit();
	    						thread.mMap.getTile(x, y).addUnit(thread.selectedUnit);
    					}else {
    						// the target contains another unit. If the unit is enemy-controlled, attack it
    					}
    					thread.selectedUnit = null;
    				}else
    					thread.selectedUnit = target;
    			}
    			
    			break;
    		}
    	}else if(event.getAction() == MotionEvent.ACTION_DOWN) {
	    	
    	}
        
        return true;
    }
    
    /**
     * Fetches the animation thread corresponding to this LunarView.
     * 
     * @return the animation thread
     */
    public DrawingThread getThread() {
        return thread;
    }

    /**
     * Installs a pointer to the text view used for messages.
     */
    public void setTextView(TextView textView) {
        mStatusText = textView;
    }

    /* Callback invoked when the surface dimensions change. */
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        thread.setSurfaceSize(width, height);
    }

    /*
     * Callback invoked when the Surface has been created and is ready to be
     * used.
     */
    public void surfaceCreated(SurfaceHolder holder) {
        thread.setRunning(true);
        thread.start();
    }

    /*
     * Callback invoked when the Surface has been destroyed and must no longer
     * be touched. WARNING: after this method returns, the Surface/Canvas must
     * never be touched again!
     */
    public void surfaceDestroyed(SurfaceHolder holder) {
        // we have to tell thread to shut down & wait for it to finish, or else
        // it might touch the Surface after we return and explode
        boolean retry = true;
        thread.setRunning(false);
        while (retry) {
            try {
                thread.join();
                retry = false;
            } catch (InterruptedException e) {
            }
        }
    }
}
