/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

// -*-C++-*- ( needed by emacs to go to c++ mode)
#pragma once
/*
   DATACOVERAGE

   This program gets the data from a mars request or file.
   If the user specifies checking time/date and cutoff,
   the data will be plotted as late against the cutoff time.
   If not, the arrival time is ignored, and quality control
   values( for conv. data) or idents ( for sat.data) will be
   plotted.
   Plotting of late arrivals override qc or ident values.

   The retrieved data is processed using the MvObs* classes.
   All the obs. are processed, and for each obs ( and subset
   if that is switched on) a line in a geopoints are produced.
   The symbol in the geopoints file are based on the contents
   of the obs. Late obs are marked, and for non-satelite data
   the data are grouped by % confidence. Satelite data are
   grouped by satelite id.

   If the data contains both satelite and conv. data, they will
   both be processed. The legend will reflect the values for
   the first type in the field, so for data not matching this
   main type ( satelite vs conv), the legend will be wrong. A
   message is printed saying that satelite and conv. data should
   not be printed together.
*/

#include <map>
#include <vector>

#include <ctype.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <Metview.h>
#include <unistd.h>
#include <time.h>
#include "MvObs.h"

#define NUMBER(a) (sizeof(a) / sizeof(a[0]))

enum
{
    LATE    = 1,
    UNKNOWN = 7
};

#ifdef MV_BUFRDC_TEST
#ifdef FORTRAN_NO_UNDERSCORE
#define gbyte_ gbyte
#endif
#endif

struct Ident_info
{
    int st_min, st_max;
    int i_min, i_max;
    int flag;
    char* txt;
};

// Change here to add new subtypes/idents for satelite data.
// The fields are :
// subtype_min,subtype_max,ident_min,ident_max,flag,text

// subtype_min and subtype_max are often the same, if given
// as a range it's inclusive ( same for idents).
// Flag is a value from 2 upwards ( 1 is used for late data).

// Note that if more than 4 ident ranges is given for the
// same subtype range, the UNKNOWN value above must be
// increased. Currently late is plotted with flag 1, qc values
// or idents from flag 2-5, and unknown as flag 6.
// More symbol markers/colors should also be added to the editor's
// attached symbol plot.
//

Ident_info ident_info[] =
    {
        {51, 53, 206, 206, 2, "SAT 206 NOAA-14"},
        {51, 53, 202, 202, 3, "SAT 202 NOAA-12"},
        {51, 53, 201, 201, 4, "SAT 201 NOAA-11"},

        {61, 63, 239, 239, 2, "SAT 206 NOAA-14"},
        {61, 63, 237, 237, 3, "SAT 202 NOAA-12"},
        {61, 63, 236, 236, 4, "SAT 201 NOAA-11"},

        {71, 73, 245, 245, 2, "SAT 245 DMSP-12"},
        {71, 73, 246, 246, 3, "SAT 246 DMSP-13"},


        {82, 88, 0, 99, 2, "METEOSAT"},
        {82, 88, 100, 199, 3, "HIMAWARI"},
        {82, 88, 200, 299, 4, "GOES"},
        {82, 88, 400, 499, 5, "INSAT"},
        //Sylvie Lamy-Thepaut : add setting for MODIS...
        // Increase the value of the unknown ... Change the default symbol
        // to add an entry...
        {87, 87, 783, 784, 6, "MODIS"},

        {121, 124, 2, 2, 2, "ERS-2"},

        {126, 126, 204, 204, 2, "SAT 204"},
        {126, 126, 246, 246, 3, "SAT 246 DMSP"},


        {127, 127, 246, 246, 2, "SAT 246 DMSP"},
        {127, 127, 245, 245, 3, "SAT 245 DMSP"},
};

//-- symbol_table goes with the one in DatacoverageDef.
//-- These values will be used if user PSYMB contains
//-- too few table values                (030929/vk)

double default_min_table[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
double default_max_table[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};

double default_marker_table[] = {0, 18, 2, 6, 5,
                                 3, 7, 9, 10, 15,
                                 17, 19, 20, 12, 8};

double default_height_table[] = {0.18, 0.12, 0.12, 0.12, 0.12,
                                 0.12, 0.12, 0.12, 0.12, 0.12,
                                 0.12, 0.12, 0.12, 0.12, 0.12};

char* default_colour_table[] = {"RED", "BLUE", "BLACK", "MAGENTA", "ORANGE",
                                "EVERGREEN", "GREY", "BRICK", "BLUE_PURPLE", "GOLD",
                                "GREENISH_BLUE", "LAVENDER", "MUSTARD", "REDDISH_PURPLE", "TANGERINE"};

#ifdef MV_BUFRDC_TEST
// The program unpacks the key manually.
extern "C" {
int gbyte_(long*, long*, long&, long&);
}
#endif

//--------------------------------------------- CoverageService ----
class CoverageService : public MvService
{
public:
    CoverageService();
    void serve(MvRequest&, MvRequest&);

private:
    // Process data and generate geopoints file
    int write_values(char*, MvObsSet&);

    // Set data related MAGICS values for plot
    void check_symbol_table_modes(MvRequest&, int);
    void check_one_symbol_table(MvRequest&, MvRequest&, const char*, double*, int);
    void set_legend_values(MvRequest&);
    void generate_info_str(MvRequest&, char*);
    char* format_date(const TDynamicTime&);


    // Data members
    MvRequest in_req;
    int nr_total_;
    int plot_ss_;
    int cutoff;
    int late_check;
    std::vector<int> numbers_;
    std::map<int, int, less<int> > subtype_nrs_;
    std::vector<long> descriptors;
    TDynamicTime check_time, in_time;
};
//--------------------------------------------------------------------------------


//------------------------------------------------ Utility class ObsValues
// Called for every message that needs to be processed.
class ObsValues
{
public:
    // Constructor
    ObsValues(MvObs&, int, TDynamicTime, int, std::vector<long>&, int);  // Called at start of a msg

    // Get symbol value
    int get_symbol(MvObs&, std::map<int, int, less<int> >&);  // Called for each subset

private:
    TDynamicTime check_time;
    int isbtype_;
    int ident_;
    int late_;
    int plot_ss_;
    int sec2_conf_;
    std::vector<long>& descriptors;

    int get_conf_value(MvObs& obs);

    void unpack(long&, long*, long*, long&, long&, long&, long&);
};
