/*
 * AnalyzeRockAction.java
 *
 * Created on August 20, 2003, 1:49 PM
 */

package PER.rover;
import PER.rover.control.*;
import java.awt.image.BufferedImage;


/**
 *
 * @author  Eric Porter
 */
public class AnalyzeRockAction implements Action {
   /** how far from rock to take picture from (in cm) */
   private final static int PICTURE_DIST = 5;
   /** how far it is from the IR to the front of the rover */
   private final static int IR_TO_FRONT_PROTO = 11;
   private final static int IR_TO_FRONT_ROVER = 2;
   
   private int time;
   private boolean lightUV;
   private int width, height;
   
   transient private Rover rov = null;
   transient private Thread myThread = null;
   transient private boolean success = false, completed = false;
   transient private int ret = 0;
   transient private boolean quit = false;
   transient private long starttime = 0;
   transient private BufferedImage image;
   transient private BufferedImage noUVImage;
   
   /** Creates a new instance of AnalyzeRockAction
    * This action expects to be called when the rover is facing a rock.  It will
    * drive up to the rock, take a picture, then back away.
    * @param lightUV Whether or not to have the UV light on while the picture
    *        is being taken.
    * @param width The width of the picture to be taken.
    * @param height The height of the picture to be taken.
    */
   public AnalyzeRockAction(boolean lightUV, int width, int height) {
      this.lightUV = lightUV;
      this.width = width;
      this.height = height;
      time = 10;
   }
   
   public boolean doAction(Rover r) {
      PER.rover.StatsLog.println(PER.rover.StatsLog.ANALYZE_ROCK);
       
      rov = r;
      myThread = new Thread() {
         public void run() {
            success = false;
            
            starttime = System.currentTimeMillis();
            
            quit = false;
            ret = analyzeRock();
            success = (ret == RoverState.SUCCESS);
            
            if (success) {
               long endtime = System.currentTimeMillis();
               time = (int)((endtime - starttime) );
            }
            completed = true;
         };
      };
      myThread.start();
      for(int i=0; i<10 && !myThread.isAlive(); i++)
         Thread.yield();
      return true;
   }
   
   public int getReturnValue() {
      return ret;
   }
   
   public String getShortSummary() {
      return "Drive to rock and take a picture.";
   }
   
   public String getSummary() {
      return getShortSummary();
   }
   
   public int getTime() {
      return time;
   }
   
   public int getTimeRemaining() {
      return time - (int)((System.currentTimeMillis() - starttime) );
   }
   
   public boolean isCompleted() {
      return completed;
   }
   
   public boolean isSuccess() {
      return success;
   }
   
   public void kill() {
      quit = true;
   }
   
   public BufferedImage getImage() {
      return image;
   }

   public BufferedImage getNoUVImage() {
      return noUVImage;
   }   

   public int analyzeRock() {
      ScanAction highSA = new ScanAction(PER.rover.Rover.USING_MARS_ROVER ? -15 : -10, -24, 24, 3);
      highSA.setBorderRocks(true);
      highSA.doAction(rov);
      while(!highSA.isCompleted())
         try{Thread.sleep(20);}catch(Exception e) {}
      if(quit == true)
         return ActionConstants.KILLED;
      if(!highSA.isSuccess())
         return highSA.getReturnValue();
      
      ScanAction lowSA = new ScanAction(PER.rover.Rover.USING_MARS_ROVER ? -25 : -20, -24, 24, 3);
      lowSA.setBorderRocks(true);
      lowSA.doAction(rov);
      while(!lowSA.isCompleted())
         try{Thread.sleep(20);}catch(Exception e) {}
      if(quit == true)
         return ActionConstants.KILLED;
      if(!lowSA.isSuccess())
         return lowSA.getReturnValue();
      
      int minDist, rockAngle;
      if(highSA.hasFoundRock() && !lowSA.hasFoundRock()) {
         minDist = highSA.closestReading();
         rockAngle = highSA.getRockAngle();
      }else if(!highSA.hasFoundRock() && lowSA.hasFoundRock()) {
         minDist = lowSA.closestReading();
         rockAngle = lowSA.getRockAngle();
      }else if(highSA.hasFoundRock() && lowSA.hasFoundRock()) {
         minDist = Math.min(highSA.closestReading(), lowSA.closestReading());
         rockAngle = lowSA.getRockAngle();
      }else //one of the scans should have found the rock
         return ActionConstants.NO_ROCK;
      
      if(Math.abs(rockAngle) >= 5) {
         //create a new TurnToAction to get near rock
         TurnToAction tta = new TurnToAction(rockAngle);
         tta.doAction(rov);
         while(!tta.isCompleted()) {
            if(quit)
               tta.kill();
            try{Thread.sleep(20);}catch(Exception e) {}
         }
         if(!tta.isSuccess())
            return tta.getReturnValue();
      }
      
      //create a new DriveToAction to get near rock
      DriveToAction dta = new DriveToAction(minDist - PICTURE_DIST - 
      (PER.rover.Rover.USING_MARS_ROVER ? IR_TO_FRONT_ROVER : IR_TO_FRONT_PROTO), 0, 
      DriveToAction.STATIC_SAFETY, true);
      dta.doAction(rov);
      while(!dta.isCompleted()) {
         if(quit)
            dta.kill();
         try{Thread.sleep(20);}catch(Exception e) {}
      }
      if(!dta.isSuccess() && dta.getReturnValue() != RoverState.OBSTACLE_DETECTED)
         return dta.getReturnValue();

      noUVImage = rov.takePicture(0, PER.rover.Rover.USING_MARS_ROVER ? -45 : -20, width, height);      
      image = rov.takePicture(0, PER.rover.Rover.USING_MARS_ROVER ? -45 : -20, width, height, lightUV);
      
      //create a new DriveToAction to get away from rock
      dta = new DriveToAction(-12, 0, DriveToAction.NO_SAFETY, false);
      dta.doAction(rov);
      while(!dta.isCompleted()) {
         if(quit)
            dta.kill();
         try{Thread.sleep(20);}catch(Exception e) {}
      }
      
      if(image == null)
         return ActionConstants.convertErrorMsg(rov.state.getStatus());
      
      if(!dta.isSuccess())
         return dta.getReturnValue();
      
      return RoverState.SUCCESS;
   }
   
}
