/***************************** 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 *************************************/

#include "MvFlexpart.h"

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string.h>
#include <assert.h>

#include "MvBinaryReader.h"
#include "MvDate.h"
#include "MvMiscelaneous.h"

//----------------------------------------------------------------
// Class to read flexpart file "header" produced by writeheader.f90
//----------------------------------------------------------------

MvFlexpartHeader::MvFlexpartHeader(const std::string& fileName)
{
    MvBinaryReader r(fileName);

    if (!r.isValid()) {
        std::cerr << "Could not open flexpart header: " << fileName << std::endl;
        exit(1);
    }

    r.skipRecMarker();
    runDate = r.read<int>();
    runTime = r.read<int>();
    r.skip(13);
    r.skipRecMarker();

    r.skipRecMarker();
    interval          = r.read<int>();
    averagingInterval = r.read<int>();
    samplingInterval  = r.read<int>();
    r.skipRecMarker();

    r.skipRecMarker();
    west  = r.read<float>();
    south = r.read<float>();
    nx    = r.read<int>();
    ny    = r.read<int>();
    dx    = r.read<float>();
    dy    = r.read<float>();
    north = south + (ny - 1) * dy;
    east  = west + (nx - 1) * dx;
    r.skipRecMarker();

    r.skipRecMarker();
    int num = r.read<int>();
    r.read(num, levels);
    r.skipRecMarker();

    r.skipRecMarker();
    r.skip(8);
    r.skipRecMarker();

    r.skipRecMarker();
    specNum      = r.read<int>() / 3;
    specPointNum = r.read<int>();
    r.skipRecMarker();

    //Species
    for (int i = 0; i < specNum; i++) {
        std::string wd, dd, sp;
        r.skipRecMarker();
        r.skip(4);  //1
        r.read(10, wd);
        r.skipRecMarker();

        r.skipRecMarker();
        r.skip(4);  //1
        r.read(10, dd);
        r.skipRecMarker();

        r.skipRecMarker();
        r.read<int>();
        r.read(10, sp);
        specNames.push_back(sp);
        r.skipRecMarker();

        //std::cout << "spec" << " " << i << " " << wd << " " << dd << " " << sp << std::endl;
    }

    //Release points

    r.skipRecMarker();
    int releaseNum = r.read<int>();
    r.skipRecMarker();

    for (int i = 0; i < releaseNum; i++) {
        MvFlexpartRelease rel;

        r.skipRecMarker();
        rel.start   = r.read<int>();
        rel.end     = r.read<int>();
        rel.levType = r.read<short>();
        r.skipRecMarker();

        r.skipRecMarker();
        rel.west   = r.read<float>();
        rel.south  = r.read<float>();
        rel.east   = r.read<float>();
        rel.north  = r.read<float>();
        rel.bottom = r.read<float>();
        rel.top    = r.read<float>();
        r.skipRecMarker();

        r.skipRecMarker();
        rel.num = r.read<int>();
        r.skip(4);  //1
        r.skipRecMarker();

        r.skipRecMarker();
        r.read(45, rel.name);  //compoint
        r.skipRecMarker();

        for (int j = 0; j < specNum; j++) {
            r.skipRecMarker();
            rel.massForSpec.push_back(r.read<float>());
            r.skipRecMarker();

            r.skipRecMarker();
            r.skip(4);
            r.skipRecMarker();

            r.skipRecMarker();
            r.skip(4);
            r.skipRecMarker();
        }

        release.push_back(rel);
    }

    r.skipRecMarker();
    method        = r.read<int>();
    hasSubGrid    = r.read<int>();
    hasConvection = r.read<int>();
    indSource     = r.read<int>();
    indReceptor   = r.read<int>();
    r.skipRecMarker();

    r.skipRecMarker();
    int acNum = r.read<int>();
    r.read<int>(acNum, ageClass);

// Uncomment this to write the orography into a csv (path needs to be set)
#if 0
    r.skipRecMarker();
    std::ofstream out;
    out.open("orog.csv");
    // Orography
    for(int i=0; i < nx; i++) {
        r.skipRecMarker();
        std::vector<float> orog(ny, 0.);
        r.read<float>(ny, orog);
        r.skipRecMarker();
        for(int j=0; j < ny; j++) {
            out << west+i*dx << "," << south+j*dy << "," << orog[j] << std::endl;
        }
    }
#endif
    //delete [] d;
}

void MvFlexpartHeader::print()
{
    std::cout << "header:" << std::endl;

    std::cout << "  runDate: " << runDate << std::endl;
    std::cout << "  runTime: " << runTime << std::endl;
    std::cout << "  interval: " << interval << std::endl;
    std::cout << "  averagingInterval: " << averagingInterval << std::endl;
    std::cout << "  samplingInterval: " << samplingInterval << std::endl;
    std::cout << "  west: " << west << std::endl;
    std::cout << "  south: " << south << std::endl;
    std::cout << "  nx: " << nx << std::endl;
    std::cout << "  ny: " << ny << std::endl;
    std::cout << "  dx: " << dx << std::endl;
    std::cout << "  dy: " << dy << std::endl;

    std::cout << "  levelNum : " << levels.size() << std::endl;
    for (size_t i = 0; i < levels.size(); i++)
        std::cout << "    level: " << levels[i] << std::endl;

    std::cout << "  species: " << specNum << std::endl;
    for (int i = 0; i < specNum; i++) {
        std::cout << "    name: " << specNames[i] << std::endl;
    }
    std::cout << "  specPointNum: " << specPointNum << std::endl;

    std::cout << "  relaseNum : " << release.size() << std::endl;
    std::cout << "    ---------------------------" << std::endl;
    for (size_t i = 0; i < release.size(); i++) {
        std::cout << "    name: " << release[i].name << std::endl;
        std::cout << "    start: " << release[i].start << std::endl;
        std::cout << "    end: " << release[i].end << std::endl;
        std::cout << "    west: " << release[i].west << std::endl;
        std::cout << "    east: " << release[i].east << std::endl;
        std::cout << "    north: " << release[i].north << std::endl;
        std::cout << "    south: " << release[i].south << std::endl;
        std::cout << "    bottom: " << release[i].bottom << std::endl;
        std::cout << "    top: " << release[i].top << std::endl;
        std::cout << "    levelUnitsType: " << release[i].levType << std::endl;
        std::cout << "    particleCount: " << release[i].num << std::endl;

        std::cout << "    massesNum : " << release[i].massForSpec.size() << std::endl;
        for (size_t j = 0; j < release[i].massForSpec.size(); j++)
            std::cout << "      mass: " << release[i].massForSpec[j] << std::endl;

        std::cout << "    ---------------------------" << std::endl;
    }

    std::cout << "  method: " << method << std::endl;
    std::cout << "  hasSubGrid: " << hasSubGrid << std::endl;
    std::cout << "  hasConvection: " << hasConvection << std::endl;
    std::cout << "  sourceUnitsType: " << indSource << std::endl;
    std::cout << "  receptorUnitsType: " << indReceptor << std::endl;

    std::cout << "  ageClasses : " << ageClass.size() << std::endl;
    for (size_t i = 0; i < ageClass.size(); i++)
        std::cout << "    ageClass: " << ageClass[i] << std::endl;
}

//----------------------------------------------------------------
// Class to read flexpart file "dates" produced by concoutput.f90
//----------------------------------------------------------------

MvFlexpartDates::MvFlexpartDates(const std::string& fileName) :
    num(0)
{
    std::ifstream in(fileName.c_str(), std::ios::in);
    if (!in.is_open()) {
        std::cerr << "Could not open flexpart dates: " << fileName << std::endl;
        exit(1);
    }

    std::string line;

    //run date and time
    while (getline(in, line)) {
        std::string dateStr = line.substr(0, 7);
        std::string timeStr = line.substr(8, 13);
        date.push_back(dateStr);
        time.push_back(timeStr);
        num++;
    }

    assert(static_cast<int>(date.size()) == num);
    assert(static_cast<int>(time.size()) == num);
}

void MvFlexpartDates::print()
{
    std::cout << "dates:" << std::endl;
    for (int i = 0; i < num; i++)
        cout << "  date: " << date[i] << "  time: " << time[i] << std::endl;
}
