/***************************** 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);
    //r.skipRecMarker();

    //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;
}
