/*=========================================================================

Program:   Orbit Visualization Tool
Source:    $Source$
Date:      $Date$
Version:   $Revision$


Copyright (c) 2000 OVT Team (Kristof Stasiewicz, Mykola Khotyaintsev,
Yuri Khotyaintsev)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification is permitted provided that the following conditions are met:

 * No part of the software can be included in any commercial package without
written consent from the OVT team.

 * Redistributions of the source or binary code must retain the above
copyright notice, this list of conditions and the following disclaimer.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT OR
INDIRECT DAMAGES  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE.

OVT Team (http://ovt.irfu.se)   K. Stasiewicz, M. Khotyaintsev, Y.
Khotyaintsev

=========================================================================*/

/*
 * 
 * Created on November 26, 2000, 10:55 PM
 */

package ovt.object;

/**
 *
 * @author  ko
 * @version 
 */

import vtk.*;

import ovt.*;
import ovt.gui.*;
import ovt.mag.*;
import ovt.beans.*;
import ovt.util.*;
import ovt.event.*;
import ovt.datatype.*;
import ovt.interfaces.*;

import java.beans.*;
import java.util.*;
import java.awt.*;
import javax.swing.*;
import java.io.*;

/**
 *
 * @author  ko
 * @version 
 */
public class FootprintDataModule extends SingleActorSatModule {
    private static final int TIME  = 0;
    private static final int VALUE = 1;
    private static final int X = 0;
    private static final int Y = 1;
    private static final int Z = 2;
    DataModule dataModule;
    double height = 0.1;
   
public FootprintDataModule(DataModule module) {
  super(module.getSat(),  "OnFieldlines", OVTCore.getImagesDir() + "fieldline.gif");
  this.dataModule = module;
}

private double[][] getData() {
    return dataModule.getData();
}

private TimeSet getDataTimeSet() {
    return dataModule.getDataTimeSet();
}


protected void validate() {
   
   double[][] data = getData();
   double min = dataModule.getMin();
   double max = dataModule.getMax();
   
   final int EARTH = 0;
   final int EQUATOR = 1;
   int we_use = EQUATOR;
   int minNumOfPoints = Integer.MAX_VALUE;
   int maxNumOfPoints = 0;
   
   int dateCount = data.length;
   Fieldline[][] fl = new Fieldline[dateCount][2];
   
   double[] r = null, r2, r3;
   double y = 1, mjd;
   for (int i=0; i<dateCount; i++) {
      mjd = data[i][TIME];
      
      r = getPosition(mjd); // GSM!!!
      fl[i] = makeFieldlines(mjd, r);
      System.out.println("fl0.size=" + fl[i][0].size() + " fl1.size=" + fl[i][1].size());
      if (fl[i][we_use].size() < minNumOfPoints) minNumOfPoints = fl[i][we_use].size();
      if (fl[i][we_use].size() > maxNumOfPoints) maxNumOfPoints = fl[i][we_use].size();
   }
   
   //minNumOfPoints = 8;
   
   vtkPoints points = new vtkPoints();
   vtkScalars scalars = new vtkScalars();
   Enumeration e;
   MagPoint p;
   for (int i=0; i<dateCount; i++) {
     e = fl[i][we_use].elements();
     for (int j=0; j<fl[i][we_use].size(); j++) {
         p = (MagPoint)e.nextElement();
         r = p.gsm;
         points.InsertNextPoint(r[X], r[Y], r[Z]);
         if (j!=0) scalars.InsertNextScalar(data[i][VALUE]);
     }
     // add the last point to fill the length to maxNumOfPoints
     for (int j=fl[i][we_use].size(); j<maxNumOfPoints; j++) {
         points.InsertNextPoint(r[X], r[Y], r[Z]);
         if (j!=0) scalars.InsertNextScalar(data[i][VALUE]);
     }
   }
   
   vtkStructuredGrid grid = new vtkStructuredGrid();
        grid.SetPoints(points);
        grid.SetDimensions(maxNumOfPoints, dateCount, 1);
        grid.GetCellData().SetScalars(scalars);
        

   vtkStructuredGridGeometryFilter filter = new vtkStructuredGridGeometryFilter();
        filter.SetInput(grid);
        
        //filter.SetExtent(0, dateCount - 1, 0, minNumOfPoints - 1, 1, 1);
        
   vtkLookupTable lut  = new vtkLookupTable();
	lut.SetHueRange(0.6667, 0);
	
        
    vtkPolyDataMapper mapper = new vtkPolyDataMapper();
	mapper.SetInput(filter.GetOutput());
	mapper.SetScalarModeToUseCellData();
        mapper.ScalarVisibilityOn();
	mapper.SetScalarRange(min, max);
	mapper.SetLookupTable(lut);
        
        
    actor = new vtkActor();
        actor.SetMapper(mapper);
        float[] rgb = ovt.util.Utils.getRGB(getColor());
        actor.GetProperty().SetColor(rgb[0], rgb[1], rgb[2]);
        actor.GetProperty().SetRepresentationToSurface();
        //actor.GetProperty().SetOpacity(0.6);
    super.validate();
}


protected Fieldline[] makeFieldlines(double mjd, double[] gsm) {
    Fieldline[] fl;
    double rmin = getMagProps().alt / Const.RE + 1.;
    MagProps magProps = getMagProps();
    
    if (gsm == null) System.out.println("NULL POSITION!!!"); 
    double alt = Const.RE;
    Fieldline fl1 = Trace.traceline(magProps, mjd, gsm,  1 * 0.001, 0, alt);
    Fieldline fl2 = Trace.traceline(magProps, mjd, gsm, -1 * 0.001, 0, alt);
      
    boolean first = true; // - first line is FL_2_EARTH
  
    // if two fotprints are close to earth - choose the shirtest line
    if ((Vect.absv(fl1.lastPoint().gsm) < rmin) && 
        (Vect.absv(fl2.lastPoint().gsm) < rmin)) {
      if ((Math.abs(fl1.length()) < Math.abs(fl2.length()))) {
        first = true;
      } else {
        first = false;
      }
    // choose the line, which footprin is close to earth
    } else if (Vect.absv(fl1.lastPoint().gsm) < rmin) {
      first = true;
    } else {
      first = false;
    }

    if (first) return new Fieldline[]{ fl1, fl2 };
    else return new Fieldline[]{ fl2, fl1 };
    
}



public void timeChanged(TimeEvent evt) {
    if (evt.getPropertyName().equals("time")) {
        if (!getDataTimeSet().overlaps(getTimeSet())) {
            invalidate();
            if (isVisible()) setVisible(false);
            setEnabled(false);
        } else setEnabled(true);
    }
}

}


