
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;

import cds.aladin.AladinData;
import cds.aladin.AladinPlugin;
import cds.aladin.Ligne;
import cds.aladin.Obj;
import cds.aladin.RepereSpectrum;
import cds.aladin.SourceStat;
import cds.tools.VOApp;
import cds.tools.VOObserver;

public class PhotControlPlug extends AladinPlugin implements VOObserver,VOApp {
   
   static String planeName = "PhotTool";
   AladinData ad=null;
   
   public String menu() { return "Photometry tool manipulation"; }
   public String description() {
      return "PLUGIN TUTORIAL:\n" +
      "This plugin is an example for photometry tools manipulation.\n" +
      "This plugin extracts the spectrum at the mouse position.";
   }   
   public String version()     { return "1.1 - Octobre 2021 -  - required Aladin >= v11.069"; }
   public String author()      { return "Pierre Fernique [CDS]"; }
   public String url()         { return "http://aladin.u-strasbg.fr/java/Plugins/PhotControlPlug.java"; }
   
   public void exec() {
      // Register this plugin as a VOObserver (see execCommand() method)
      aladin.addObserver(this,VOApp.MEASURE | VOApp.STACKEVENT | VOApp.MOUSEEVENT );
      
      // Set the list of stat metrics 
      String statList = aladin.setStatMask("-median,-pixels");
      System.out.println("Statistics: "+statList);
      
      // get or create a dedicated tool plane
      try {
         ad = getOrCreateToolPlane();
         System.out.println("The phot tools must be stored in \""+ad.getLabel()+"\" tool plane");
      } catch( Exception e ) { e.printStackTrace(); }
      
   }
   
   // Find or create a tool plane
   private AladinData getOrCreateToolPlane() throws Exception {
      
      // Is there already a Tool Plane in the Aladin stack ?
      String [] planeID = aladin.getAladinStack();
      for( int i=0; i<planeID.length; i++ ) {
         AladinData sd = aladin.getAladinData(planeID[i]);
         if( sd.getPlaneType().indexOf("Tool")>=0 ) return sd;
      }
      
      // otherwise, create one
      return aladin.createAladinTool(planeName);
   }
   
   // Call by Aladin when the stack is modified, or an event on phot tools occured
   public String execCommand(String cmd) {
      System.out.println("Aladin event: => "+cmd);
      rescanPhotTool();
      return "";
   }
   
   HashMap<Obj,Integer> alreadyScanned = new HashMap<>();
   
   // Scanning the dedicated Tool plane generated by the Plugin
   // and display the statistics associated to each Phot objects (Cicle, Polygon)
   private void rescanPhotTool() {
      try {
         
         // Get the plane in background
         AladinData adbg = aladin.getAladinImage();
         String planeType = adbg.getPlaneType();
         System.out.println("Phot stats from "+adbg.getLabel()+" plane ("+planeType+")...");
         boolean isCube = planeType.indexOf("Blink")>=0 || planeType.indexOf("Cube")>=0;
         
         HashMap<Obj,Integer> scanned = new HashMap<>();
         
         // Scanning of the Tool objects in the dedicated tool plane
         Iterator<Obj> it = ad.iteratorObj();
         while( it.hasNext() ) {
            Obj o = it.next();
            if( !o.hasPhot() || !o.isVisible() ) continue;
            
            // Manage the list of objects already scanned
            int cle = o.getStatsHashcode(adbg);
            scanned.put(o,cle);
            Integer lastCle = alreadyScanned.get(o);
            if( lastCle!=null && lastCle==cle ) {
               System.out.println("Obj "+o.hashCode()+ " stats already known");
               continue;
            }
            
            double stats [] = o.getStatistics(adbg);
            if( stats==null ) continue;
            
            String type = o instanceof Ligne ? "polygon" 
                        : o instanceof SourceStat ? "circle" 
                        : o instanceof RepereSpectrum ? "point" 
                        : "Other??";
            
            System.out.println("Obj "+type+" hash="+o.hashCode()
               +"=>  cnt="+stats[0]+",sum="+stats[1]+",sigma="+stats[2]+",surf="+stats[3]+",min="+stats[4]+",max="+stats[5]);
            
            // For a cube, also compute stats for the middle frame and the last frame of the cube
            if( isCube ) {
               int z = adbg.getDepth();
               stats = o.getStatistics(adbg, z/2 );
               System.out.println("      middle frame ("+(z/2)+"): "
                  +"=>  cnt="+stats[0]+",sum="+stats[1]+",sigma="+stats[2]+",surf="+stats[3]+",min="+stats[4]+",max="+stats[5]);
               
               stats = o.getStatistics(adbg, z-1 );
               System.out.println("      last frame ("+(z-1)+") : "
                  +"=>  cnt="+stats[0]+",sum="+stats[1]+",sigma="+stats[2]+",surf="+stats[3]+",min="+stats[4]+",max="+stats[5]);
               
               
               // Calcul des perfs
               long cnt=0L;
               long t = System.currentTimeMillis();
               for( int i=0; i<z; i++ ) {
                  stats = o.getStatistics(adbg, i );
                  if( i%100==0 ) System.out.println("stat "+i+"...");
                  cnt+=stats[0];
               }
               long t1 = System.currentTimeMillis();
               System.out.println("Extract statistics for "+cnt+" pixels through "+z+" frames ("+cnt/z+" per frame) in "
                  +(t1-t)+"ms => "+((t1-t)/(double)z)+"ms per frame");
            }

            // Pixels access (by triplet array) - display 2 values here
            double [] raDecVal = o.getStatisticsRaDecPix(adbg,0);
            if( raDecVal.length>0 ) {
               int i=0;
               System.out.println("First pixel "+(i/3)+" (frame 0) ra="+raDecVal[i]+" dec="+raDecVal[i+1]+" pix="+raDecVal[i+2]);
               i = raDecVal.length-3;
               System.out.println("Last pixel  "+(i/3)+" (frame 0) ra="+raDecVal[i]+" dec="+raDecVal[i+1]+" pix="+raDecVal[i+2]);
            }
            
         }
         
         // update the list of known scanned objects
         for( Obj o : alreadyScanned.keySet() ) { 
              if( !scanned.containsKey( o ) ) System.out.println("Obj "+o.hashCode()+ " has been removed in Aladin");
         }
         alreadyScanned = scanned;
         
      } catch( Exception e ) { e.printStackTrace(); }
   }
   
   
   // VOApp & VOObserver methods (not used here)
   public String putVOTable(InputStream in, String label) { return null; }
   public String putVOTable(VOApp app, InputStream in, String label) { return null; }
   public InputStream getVOTable(String dataID) { return null; }
   public String putFITS(InputStream in, String label) { return null; }
   public InputStream getFITS(String dataID) { return null; }
   public void showVOTableObject(String[] oid) { }
   public void selectVOTableObject(String[] oid) { }
   public void setVisible(boolean flag) { }
   public void addObserver(VOObserver app, int eventMasq) { }
   public void pixel(double pixValue) { }
   public void position(double raJ2000, double deJ2000) { }
}