/***************************************************************************
 *   Copyright (C) 2005 by Nicolas PASCAL                                  *
 *   nicolas.pascal@icare.univ-lille1.fr                                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef IIRFILEDATA_H
#define IIRFILEDATA_H

#include "hdffiledata.h"
#include "pixel.h"
#include "satellitefiledata.h"

static const int GET_SHOT_TIME_INDEX_TRACE=0;
static const int BRUTE_FORCE_SEARCH=1;

/**
manage the reading of the CALIPSO IIR files.
At this time, treats only L2 Track files. For Swath files, some methods need to be completed.
@author Nicolas PASCAL
*/
class IIRFileData : public SatelliteFileData, public HDFFileData {

public:
    /**
    defines the possible types of IIR products
    */
    enum ProductType{
            UNDEFINED,
            L1,
            L2_TRACK,
            L2_SWATH,
    };
    /** number of pixels of the IIR swath (at 1 km resolution) */
    static const int IIR_swath_size;
    /** maximum number of records for an IIR L2 half-orbit. Useful for static buffers allocations */
    static const int nb_record_max;

private:
    /**
    the level of the product
    */
    int level;
    /**
    the type of the product
    */
    ProductType product_type;
    /**
    wether the data in this file have been taken during day (true) or night(false)
    */
    bool day_mode;

// // // //     float *lat_data;
// // // //     float *lon_data;
// // // //     double *time_data;

    /** a list of pixels data, sorted by increasing latitude, then increasing longitude */
    vector<PixelType> v_pixel;

    static const string latitude_sds_name;
    static const string longitude_sds_name;
    /** Can't be static : this SDS is named "Lidar_Shot_Time" in IIR L1 products and "LIDAR_Shot_Time" in IIR L2 products */
    string time_sds_name;
    /** default acceptable tolerance between 2 colocated measures */
    static const float colocation_tolerance;

    int lat_lon_index_max[2];

    void init();
    /**
    @brief Check is a the file is a valid IIR data file ( the analysis is done with a filename parsing, not on the data )
    @throw invalid_filename if the filename does not match the file pattern
    @param short_filename string : the filename without its path
    */
    void check_filename( const string& short_filename ) const;
    /**
    Once the filename has been checked (that's a precondition : no verification on it are done in this method), some informations can be extracted of it :
    - the level of the data
    - the date
    - the hour
    @param short_filename string : the filename without its path
    */
    void parse_filename( const string& short_filename );
    void set_time_coverage();
    void set_lat_lon_index_max();
protected:
    /**
     * @brief load the list data pixels
     */
    virtual void load_v_pixel() ;

public:
    /**
    Constructor
    @param _name the name (path+filename) of the file to be opened
    @param mode the opening mode. LIMITATION : only "r" mode treated at this time
    */
    IIRFileData(const string& _name="", const string& mode="r");
    /**
    Destructor
    */
    ~IIRFileData();
    /**
    Check if the file contains day or night data
    @return true if the file contains day data
    */
    const bool is_day() const;
    /**
    read the latitudes data in this file, and fill data with it
    @param data the array that will contain the latitudes once the method is ended
    */
    void get_latitude_data(float* data);
    /**
    read the longitudes data in this file, and fill data with it
    @param data the array that will contain the latitudes once the method is ended
    */
    void get_longitude_data(float* data);
    /**
    read the time data in this file, and fill data with it
    @param data the array that will contain the time once the method is ended
    */
    void get_time_data(double* data);
    /**
    @brief Read the number of track measures contained in this file (in pixels)
    @return the size of the track
    */
    const int get_track_size() const ;
    /**
    @brief Read the size of the swath (in pixels)
    @return the size of the swath
    */
    const int get_swath_size() const ;

    /**
     * @brief search the index of the nearest point in the data to (@a lat , @a lon )
     * If @a coloc_tolerance is given, it will compute only the distance of the points that have a distance to ( @a lat, @a lon ) inferior to @a coloc_tolerance
     * @param near_point_idx the indexes of the nearest point found (or  {-1,-1} if not found)
     * @param lat the latitude
     * @param lon the longitude
     * @param time the time of the observation. If -1., skipped
     * @param coloc_tolerance the -/+ maximal tolerance for 2 points considered as colocated
     * @return true if found
     */
    const bool get_index(const float &lat, const float& lon, const double &time, int * near_point_idx, const float coloc_tolerance=IIRFileData::colocation_tolerance);
    /**
     * find the row index of the nearest point in the data of this file to (lat,lon,time). Be careful, it will return a valid index : this method doesn't check if the point given in parametre is contained in this file. Use the contains_data_at to check it first.
     * @param lat the latitude of the event
     * @param lon the longitude of the event
     * @param time the time of the event
     * @return the nearest point row index
     */
     const int get_nearest_point_index( const float &lat, const float &lon,const double &time);
    /**
     * check if this file has data coincident with (lat,lon,time)
     * @param lat the latitude of the event
     * @param lon the longitude of the event
     * @param time the time of the event
     * @return
     */
    const bool contains_data_at(const float &lat,const float &lon, const double &time) const;
    /**
    load the geolocations data. This method is used to make the search of the indexes of a (lat,lon,time) point faster.
    */
    void load_geolocation_data();
    /**
    free eventually loaded geolocation data
    */
    void free_geolocation_data();
    /**
    Check if the geolocation data have been already loaded
    @return true if the lat_lon data have already been loaded
    */
    const bool is_geolocation_data_loaded() const;

    /**
     * @brief find the index of the nearest point to (lat,lon) in the data.
     * If (lat,lon) is not found or out of the colocalisation_frame, returned indexes are [-1,-1]
     * @param lat the latitude
     * @param lon the longitude
     * @param nearest_pix_idx the index of the nearest measure. -1 if no coincidence found.
     * @param colocation_tolerance the acceptable bias (in km or degrees. Supposed to be in, a plane approximation) between [lat,lon] and the nearest data point.
     * @return true if the coincidence has been found
     */
    const bool get_index(const float &lat, const float& lon, int &nearest_pix_idx, const float colocation_tolerance=IIRFileData::colocation_tolerance);

        /**
     * @brief compute the distance to (lat,lon) of the nearest point in the data
     * If @a coloc_tolerance is given, it will compute only the distance of the points that have a distance to ( @a lat, @a lon ) inferior to @a coloc_tolerance
     * @param lat the latitude
     * @param lon the longitude
     * @param coloc_tolerance the -/+ maximal tolerance for 2 points considered as colocated
     * @return the distance to the nearest point, or -1 if no point in the colocalisation frame has been found.
     */
    const float get_nearest_point_distance(const float &lat,const float &lon,const float coloc_tolerance=IIRFileData::colocation_tolerance);
    /**
     * @brief check if this file has eventually data coincident with (lat,lon)
     * Actually, it only tests if (lat,lon) is contained in the data's bounding rectangle.
     * @param lat the latitude of the event
     * @param lon the longitude of the event
     * @param tolerance acceptable bias between the nearest point in the data and the given (lat,lon) point
     * @return true if a point in the data has been found in the colocation frame
     */
    const bool contain_location(const float &lat,const float &lon, const double &tolerance=IIRFileData::colocation_tolerance);
    /**
     * @brief check if the file has possible (lat,lon) coincidence
     * @warning it's an EVENTUAL coincidence. That is not a proof !!!
     * @param lat latitude
     * @param lon longitude
     * @param time time
     * @param colocation_tolerance the acceptable bias (in km or degrees. Supposed to be in, a plane approximation) between [lat,lon] and the nearest data point.
     * @return true if can eventually contain a coincidence with the point.
     * @warning at this time always true. I don't have a good way to do it
     */
    const bool contain_data(const float &lat, const float &lon, const double &time, const double &colocation_tolerance=IIRFileData::colocation_tolerance) ;
    /**
     * @brief retrieve the coordinates of a pixel using its index
     * @param ipix [IN] index of the pixel
     * @param lat [OUT] latitude of the pixel
     * @param lon [OUT] longitude of the pixel
     * @param time [OUT] timestamp of the pixel
     */
    virtual void get_pixel_coord ( const vector < int > & ipix, float &lat, float &lon, double &time ) {
        UnimplementedMethod e(__FILE__,__LINE__,__PRETTY_FUNCTION__);
        throw e;
    };

    /**
     * @brief build the list of indices of pixels that are in colocation tolerance, sorted by increasing distance to (lat,lon)
     * If (lat,lon) is not found or out of the colocalisation_frame, returns an empty vector
     * @param lat the latitude
     * @param lon the longitude
     * @param colocation_tolerance the acceptable bias (in km or degrees. Supposed to be in, a plane approximation) between [lat,lon] and the nearest data point.
     * @return the list of indices of pixels
     */
     virtual void get_vindex(vector < vector < int > > &v_index, const float &lat, const float& lon,
                                            const float colocation_tolerance ) {
        UnimplementedMethod e(__FILE__,__LINE__,__PRETTY_FUNCTION__);
        throw e;
     };
   /**
    * @brief closes the file.
    */
    virtual void close_data_file() {
        free_hdf_file();
    };
   /**
    * @brief opens the file.
    */
    virtual void open_data_file() {
        load_hdf_file();
    };

};

#endif