/******************************************************************************
 * $Id$
 *
 * Project:  MSG Native Reader
 * Purpose:  Base class for reading in the headers of MSG native images
 * Author:   Frans van den Bergh, fvdbergh@csir.co.za
 *
 ******************************************************************************
 * Copyright (c) 2005, Frans van den Bergh <fvdbergh@csir.co.za>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 ****************************************************************************/

#ifndef MSG_READER_CORE_H
#define MSG_READER_CORE_H

#include "msg_basic_types.h"
#include <stdio.h>
#include "cpl_vsi.h"

namespace msg_native_format
{

const unsigned int MSG_NUM_CHANNELS = 12;

typedef struct
{
    double vc;
    double A;
    double B;
} Blackbody_lut_type;

typedef enum
{
    VIS0_6 = 2,
    VIS0_8 = 4,
    NIR1_6 = 8,
    IR3_9 = 16,
    IR6_2 = 32,
    IR7_3 = 64,
    IR8_7 = 128,
    IR9_7 = 256,
    IR10_8 = 512,
    IR12_0 = 1024,
    IR13_4 = 2048,
    HRV = 4096
} Msg_channel_names;

class Msg_reader_core
{
  public:
    explicit Msg_reader_core(const char *fname);
    explicit Msg_reader_core(VSILFILE *fp);
    virtual ~Msg_reader_core()
    {
    }

    bool get_open_success() const
    {
        return _open_success;
    }

#ifndef GDAL_SUPPORT
    virtual void radiance_to_blackbody(
        int using_chan_no =
            0) = 0;  // can override which channel's parameters to use
    virtual double *get_data(int chan_no = 0) = 0;
#endif

    unsigned int get_lines() const
    {
        return _lines;
    }
    unsigned int get_columns() const
    {
        return _columns;
    }

    void get_pixel_geo_coordinates(unsigned int line, unsigned int column,
                                   double &longitude, double &latitude)
        const;  // x and y relative to this image, not full disc image
    void get_pixel_geo_coordinates(
        double line, double column, double &longitude,
        double
            &latitude);  // x and y relative to this image, not full disc image
    double compute_pixel_area_sqkm(double line, double column);

    static const Blackbody_lut_type Blackbody_LUT[MSG_NUM_CHANNELS + 1];

    unsigned int get_year() const
    {
        return _year;
    }
    unsigned int get_month() const
    {
        return _month;
    }
    unsigned int get_day() const
    {
        return _day;
    }
    unsigned int get_hour() const
    {
        return _hour;
    }
    unsigned int get_minute() const
    {
        return _minute;
    }

    unsigned int get_line_start() const
    {
        return _line_start;
    }
    unsigned int get_col_start() const
    {
        return _col_start;
    }

    float get_col_dir_step() const
    {
        return _col_dir_step;
    }
    float get_line_dir_step() const
    {
        return _line_dir_step;
    }
    float get_hrv_col_dir_step() const
    {
        return _hrv_col_dir_step;
    }
    float get_hrv_line_dir_step() const
    {
        return _hrv_line_dir_step;
    }

    unsigned int get_f_data_offset() const
    {
        return _f_data_offset;
    }
    unsigned int get_visir_bytes_per_line() const
    {
        return _visir_bytes_per_line;
    }
    unsigned int get_visir_packet_size() const
    {
        return _visir_packet_size;
    }
    unsigned int get_hrv_bytes_per_line() const
    {
        return _hrv_bytes_per_line;
    }
    unsigned int get_hrv_packet_size() const
    {
        return _hrv_packet_size;
    }
    unsigned int get_interline_spacing() const
    {
        return _interline_spacing;
    }

    const unsigned char *get_band_map() const
    {
        return _bands;
    }

    const CALIBRATION *get_calibration_parameters() const
    {
        return _calibration;
    }
    const IMAGE_DESCRIPTION_RECORD &get_image_description_record() const
    {
        return _img_desc_record;
    }

  private:
    void read_metadata_block(VSILFILE *fp);

  protected:
    static int _chan_to_idx(Msg_channel_names channel);

    unsigned int _lines;
    unsigned int _columns;

    unsigned int _line_start;
    unsigned int _col_start;

    float _col_dir_step;
    float _line_dir_step;
    float _hrv_col_dir_step;
    float _hrv_line_dir_step;

    MAIN_PROD_HEADER _main_header;
    SECONDARY_PROD_HEADER _sec_header;
    CALIBRATION _calibration[MSG_NUM_CHANNELS];
    IMAGE_DESCRIPTION_RECORD _img_desc_record;

    unsigned int _f_data_offset;
    unsigned int _f_data_size;
    unsigned int _f_header_offset;
    unsigned int _f_header_size;
    unsigned int _f_trailer_offset;
    unsigned int _f_trailer_size;

    unsigned int _visir_bytes_per_line;  // packed length of a VISIR line,
                                         // without headers
    unsigned int _visir_packet_size;  // effectively, the spacing between lines
                                      // of consecutive bands in bytes
    unsigned int _hrv_bytes_per_line;
    unsigned int _hrv_packet_size;
    unsigned int _interline_spacing;

    unsigned char _bands[MSG_NUM_CHANNELS];

    unsigned int _year;
    unsigned int _month;
    unsigned int _day;
    unsigned int _hour;
    unsigned int _minute;

    bool _open_success;
};

}  // namespace msg_native_format

#endif
