/*
 * This file is a part of EpnTAPClient.
 * This program aims to provide EPN-TAP support for software clients, like CASSIS spectrum analyzer.
 * See draft specifications: https://voparis-confluence.obspm.fr/pages/viewpage.action?pageId=559861
 * Copyright (C) 2016 Institut de Recherche en Astrophysique et Planétologie.
 *
 * 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 3 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, see
 * <http://www.gnu.org/licenses/>.
 */
package eu.omp.irap.vespa.epntapclient.granule;

import eu.omp.irap.vespa.votable.votable.VOTableCtrl;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import eu.omp.irap.vespa.votable.votable.VOTableException.CanNotParseDataException;
import eu.omp.irap.vespa.votable.votabledata.VOTableData;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author N. Jourdane
 */
public class GranuleCtrl {

	/** The logger for this class  */
	private static final Logger LOGGER = Logger.getLogger(GranuleCtrl.class.getName());
        
    /**
     * The data to parse
     */
    private VOTableData data;

    /**
     * Constructor of GranuleCtrl
     *
     * @param data The VOTable data to parse.
     */
    public GranuleCtrl(VOTableData data) {
        this.data = data;
    }

    /**
     * Get a Granule object from a VOTable data row.
     *
     * @param rowId the row identified
     * @return the granule at the position rowId in the VOTable data.
     * @throws CanNotParseDataException The column name was not found in the list.
     */
    public Granule getGranuleFromVOTableRow(int rowId) throws CanNotParseDataException {
        //@noformat
        Granule g = new Granule(parseString(rowId, GranuleEnum.GRANULE_UID));
        g.setGranuleGid(parseString(rowId, GranuleEnum.GRANULE_GID));
        g.setObsId(parseString(rowId, GranuleEnum.OBS_ID));
        g.setDataproductType(parseString(rowId, GranuleEnum.DATAPRODUCT_TYPE));
        g.setTargetName(parseString(rowId, GranuleEnum.TARGET_NAME));
        g.setTargetClass(parseString(rowId, GranuleEnum.TARGET_CLASS));
        g.setTimeMin(parseDouble(rowId, GranuleEnum.TIME_MIN));
        g.setTimeMax(parseDouble(rowId, GranuleEnum.TIME_MAX));
        g.setTimeSamplingStepMin(parseDouble(rowId, GranuleEnum.TIME_SAMPLING_STEP_MIN));
        g.setTimeSamplingStepMax(parseDouble(rowId, GranuleEnum.TIME_SAMPLING_STEP_MAX));
        g.setTimeExpMin(parseDouble(rowId, GranuleEnum.TIME_EXP_MIN));
        g.setTimeExpMax(parseDouble(rowId, GranuleEnum.TIME_EXP_MAX));
        g.setSpectralRangeMin(parseDouble(rowId, GranuleEnum.SPECTRAL_RANGE_MIN));
        g.setSpectralRangeMax(parseDouble(rowId, GranuleEnum.SPECTRAL_RANGE_MAX));
        g.setTimeSamplingStepMin(parseDouble(rowId, GranuleEnum.TIME_SAMPLING_STEP_MIN));
        g.setTimeSamplingStepMax(parseDouble(rowId, GranuleEnum.TIME_SAMPLING_STEP_MAX));
        g.setSpectralResolutionMin(parseDouble(rowId, GranuleEnum.SPECTRAL_RESOLUTION_MIN));
        g.setSpectralResolutionMax(parseDouble(rowId, GranuleEnum.SPECTRAL_RESOLUTION_MAX));
        g.setC1Min(parseDouble(rowId, GranuleEnum.C1MIN));
        g.setC1Max(parseDouble(rowId, GranuleEnum.C1MAX));
        g.setC2Min(parseDouble(rowId, GranuleEnum.C2MIN));
        g.setC2Max(parseDouble(rowId, GranuleEnum.C2MAX));
        g.setC3Min(parseDouble(rowId, GranuleEnum.C3MIN));
        g.setC3Max(parseDouble(rowId, GranuleEnum.C3MAX));
        g.setSRegion(parseString(rowId, GranuleEnum.S_REGION));
        g.setC1ResolMin(parseDouble(rowId, GranuleEnum.C1_RESOL_MIN));
        g.setC1ResolMax(parseDouble(rowId, GranuleEnum.C1_RESOL_MAX));
        g.setC2ResolMin(parseDouble(rowId, GranuleEnum.C2_RESOL_MIN));
        g.setC2ResolMax(parseDouble(rowId, GranuleEnum.C2_RESOL_MAX));
        g.setC3ResolMin(parseDouble(rowId, GranuleEnum.C3_RESOL_MIN));
        g.setC3ResolMax(parseDouble(rowId, GranuleEnum.C3_RESOL_MAX));
        g.setSpatialFrameType(parseString(rowId, GranuleEnum.SPATIAL_FRAME_TYPE));
        g.setIncidenceMin(parseDouble(rowId, GranuleEnum.INCIDENCE_MIN));
        g.setIncidenceMax(parseDouble(rowId, GranuleEnum.INCIDENCE_MAX));
        g.setEmergenceMin(parseDouble(rowId, GranuleEnum.EMERGENCE_MIN));
        g.setEmergenceMax(parseDouble(rowId, GranuleEnum.EMERGENCE_MAX));
        g.setPhaseMin(parseDouble(rowId, GranuleEnum.PHASE_MIN));
        g.setPhaseMax(parseDouble(rowId, GranuleEnum.PHASE_MAX));
        g.setInstrumentHostName(parseString(rowId, GranuleEnum.INSTRUMENT_HOST_NAME));
        g.setInstrumentName(parseString(rowId, GranuleEnum.INSTRUMENT_NAME));
        g.setMeasurementType(parseString(rowId, GranuleEnum.MEASUREMENT_TYPE));
        g.setProcessingLevel(parseInteger(rowId, GranuleEnum.PROCESSING_LEVEL));
        g.setCreationDate(parseDate(rowId, GranuleEnum.CREATION_DATE));
        g.setModificationDate(parseDate(rowId, GranuleEnum.MODIFICATION_DATE));
        
        g.setReleaseDate(parseDate(rowId, GranuleEnum.RELEASE_DATE));
        
        g.setServiceTitle(parseString(rowId, GranuleEnum.SERVICE_TITLE));
        g.setAccessUrl(parseString(rowId, GranuleEnum.ACCESS_URL));
        g.setAccessFormat(parseString(rowId, GranuleEnum.ACCESS_FORMAT));
        g.setThumbnailUrl(parseString(rowId, GranuleEnum.THUMBNAIL_URL));
        g.setAccessEstsize(parseInteger(rowId, GranuleEnum.ACCESS_ESTSIZE));
        
        
        
        //@format

        if (!g.isValid()) {
            throw new IllegalArgumentException("One or more EPN parameter is null.");
        }
        return g;
    }

    /**
     * @return A list of Granules from a VOTable, where each Granule is a row of the VOTable data.
     * @throws CanNotParseDataException If the granule can not be parsed or the column name was not
     * found in the list.
     */
    public List<Granule> getGranules() throws CanNotParseDataException {
        if (!isV2()) {
            throw new CanNotParseDataException(
                    "The EPN-CORE is not v2, which is the only suported version");
        }
        List<Granule> granules = new ArrayList<>();

        if (data != null) {
            for (int rowId = 0; rowId < data.getNbRows(); rowId++) {

//                            try {
                granules.add(getGranuleFromVOTableRow(rowId));
//                            }catch(CanNotParseDataException e) {
//                                e.printStackTrace();
//                                System.out.println("cannot parse row "+rowId);
//                            }
            }
        }
        return granules;
    }

    /**
     * @return true if the VOTable data implements the EpnCoreV2.
     */
    public boolean isV2() {
        return !data.isContainingColumnName("index");
    }

    /**
     * Parse a Date value in the VOTable data at the specified row and column.
     *
     * @param rowId The row identifier
     * @param granule The Granule enumeration, representing the column name.
     * @return The value as Date.
     * @throws CanNotParseDataException The column name was not found in the list.
     */
    private Date parseDate(int rowId, GranuleEnum granule) throws CanNotParseDataException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd");
        Date date = new Date();
        try {
            date = sdf.parse((String) data.getCell(rowId, granule.toString()));
        } catch (ParseException ex) {
// GFI - commented 
//            ex.printStackTrace(System.err);
//            LOGGER.warning(ex.getMessage());
            return new Date();
        }

        return date;
    }

    /**
     * Parse a Double value in the VOTable data at the specified row and column.
     *
     * @param rowId The row identifier
     * @param granule The Granule enumeration, representing the column name.
     * @return The value as Double.
     * @throws CanNotParseDataException The column name was not found in the list.
     */
    private Double parseDouble(int rowId, GranuleEnum granule) throws CanNotParseDataException {
        Double d = null;
        Object lObj = data.getCell(rowId, granule.toString());
        if (lObj instanceof Double) {
            d = (Double) lObj;
        } else if (lObj instanceof Float) {
            d = new Double((Float) lObj);
        }
        return d == null ? Double.NaN : d;
    }

    /**
     * Parse a Double value in the VOTable data at the specified row and column.
     *
     * @param rowId The row identifier
     * @param granule The Granule enumeration, representing the column name.
     * @return The value as Double.
     * @throws CanNotParseDataException The column name was not found in the list.
     */
    private Integer parseInteger(int rowId, GranuleEnum granule) {
        try {
            return (Integer) data.getCell(rowId, granule.toString());
        } catch (CanNotParseDataException ex) {
            ex.printStackTrace(System.err);
            LOGGER.warning(ex.getMessage());
            return 0;
        }
    }

    /**
     * Parse a String value in the VOTable data at the specified row and column.
     *
     * @param rowId The row identifier
     * @param granule The Granule enumeration, representing the column name.
     * @return The value as String.
     * @throws CanNotParseDataException The column name was not found in the list.
     */
    private String parseString(int rowId, GranuleEnum granule)  {
        
        try {
            return (String) data.getCell(rowId, granule.toString());
        } catch (CanNotParseDataException ex) {
            ex.printStackTrace(System.err);
           LOGGER.warning(ex.getMessage());
           return null;
        }
    }

}
