/*

  xmunipack - fits meta-info


  Copyright © 2009-2011, 2019 F.Hroch (hroch@physics.muni.cz)

  This file is part of Munipack.

  Munipack 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.

  Munipack 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 Munipack.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "xmunipack.h"
#include <fitsio.h>
#include <math.h>
#include <vector>
#include <wx/wx.h>
#include <wx/uri.h>
#include <wx/filesys.h>

#ifdef __WXDEBUG__
#include <wx/debug.h>
#endif

using namespace std;

// -------- xEmptyImage

class xEmptyImage: public wxImage
{
public:
  xEmptyImage(): wxImage(10,10) { SetRGB(wxRect(0,0,10,10),128,128,128); }
};


// --------  FitsMetaHdu


// to constructs from a full FITS file
FitsMetaHdu::FitsMetaHdu(const FitsHdu& hdu, const wxImage& ico):
  ncols(0),type(hdu.Type()),subtype(HDU_HEAD), nrows(0),
  type_str(hdu.Type_str()),icon(ico.IsOk() ? ico : xEmptyImage())
{
  for(size_t i = 0; i < hdu.GetCount(); i++)
    Add(hdu.Item(i));

  if( type == HDU_IMAGE ) {

    const FitsArray array(hdu);
    for(int i = 0; i < array.Naxis(); i++)
      naxes.push_back(array.Naxes(i));

    subtype = array.Flavour();
    subtype_str = array.Flavour_str();

  }
  else if( type == HDU_TABLE ) {

    const FitsTable table(hdu);
    ncols = table.Width();
    nrows = table.Height();
    subtype = table.Flavour();
    subtype_str = table.Flavour_str();
  }
}

// to construct from parameters (for XML archive)
FitsMetaHdu::FitsMetaHdu(const wxArrayString& h, const wxImage& i, int nc,
			 long nr, const std::vector<long>& na,
			 const wxString& t, const wxString& st):
  ncols(nc),type(HDU_UNKNOWN),subtype(HDU_DUMMY),nrows(nr),
  naxes(na),type_str(t),subtype_str(st),icon(i.IsOk() ? i : xEmptyImage())
{
  for(size_t l = 0; l < h.GetCount(); l++)
    Add(h[l]);

  if( type_str == "Head" )
    type = HDU_HEAD;
  else if( type_str == "Image" )
    type = HDU_IMAGE;
  else if( type_str == "Table" )
    type = HDU_TABLE;

  if( subtype_str == "Line" )
    subtype = HDU_IMAGE_LINE;
  else if( subtype_str == "Frame" )
    subtype = HDU_IMAGE_FRAME;
  else if( subtype_str == "Cube" )
    subtype = HDU_IMAGE_CUBE;
}

size_t FitsMetaHdu::Naxis() const
{
  return naxes.size();
}

long FitsMetaHdu::Naxes(size_t n) const
{
  if( 0 <= n && n < naxes.size() )
    return naxes[n];
  else
    return 0;
}

std::vector<long> FitsMetaHdu::GetNaxes() const
{
  return naxes;
}

long FitsMetaHdu::Width() const
{
  return Naxes(0);
}

long FitsMetaHdu::Height() const
{
  return Naxes(1);
}

long FitsMetaHdu::Nrows() const
{
  return nrows;
}

int FitsMetaHdu::Ncols() const
{
  return ncols;
}

int FitsMetaHdu::Type() const
{
  return type;
}

int FitsMetaHdu::SubType() const
{
  return subtype;
}

wxString FitsMetaHdu::Type_str() const
{
  return type_str;
}

wxString FitsMetaHdu::SubType_str() const
{
  return subtype_str;
}

wxImage FitsMetaHdu::GetIcon() const
{
  wxASSERT(icon.IsOk());
  return icon;
}

void FitsMetaHdu::SetIcon(const wxImage& i)
{
  wxASSERT(i.IsOk());
  icon = i;
}

wxString FitsMetaHdu::GetControlLabel() const
{
  wxString label = GetKey("EXTNAME");
  if( label.IsEmpty() )
    label = Type_str();
  return label;
}


// ------- FitsMeta


FitsMeta::FitsMeta():type(FITS_UNKNOWN),size(wxInvalidSize) {}

FitsMeta::FitsMeta(const FitsFile& fits, const wxImage& ico,
		   const std::vector<wxImage>& list):
  url(fits.GetURL()),type_str(fits.Type_str()),type(fits.Type()),
  icon(ico.IsOk() ? ico : xEmptyImage()), size(wxInvalidSize)
{
  wxASSERT(fits.Status() && list.size() == fits.HduCount());

  for(size_t k = 0; k < fits.HduCount(); k++)
    hdu.push_back(FitsMetaHdu(fits.Hdu(k),list[k]));

  wxFileName fn(wxFileSystem::URLToFileName(url));
  size = fn.GetSize();
}

FitsMeta::FitsMeta(const wxString& u, const wxString& t,
		   const vector<FitsMetaHdu>& h, const wxImage& i,
		   wxULongLong s):
  url(u),type_str(t),type(FITS_UNKNOWN),hdu(h),
  icon(i.IsOk() ? i : xEmptyImage()), size(s)
{
  if( type_str == "Gray image" )
    type = FITS_GRAY;
  else if( type_str == "Colour image" )
    type = FITS_COLOUR;
  else if( type_str == "Multi layer" )
    type = FITS_MULTI;
}

wxImage FitsMeta::GetIcon() const
{
  return icon;
}

void FitsMeta::SetIcon(const wxImage& i)
{
  wxASSERT(i.IsOk());
  icon = i;
}

size_t FitsMeta::HduCount() const
{
  return hdu.size();
}

FitsMetaHdu FitsMeta::Hdu(size_t n) const
{
  wxASSERT(0 <= n && n < hdu.size() );
  return hdu[n];
}

FitsMetaHdu *FitsMeta::GetHdu(size_t n)
{
  wxASSERT(0 <= n && n < hdu.size() );
  return &hdu[n];
}

int FitsMeta::Type() const
{
  return type;
}

wxString FitsMeta::Type_str() const
{
  return type_str;
}

wxString FitsMeta::Mtime() const
{
  wxURI uri(url);
  wxFileName name(uri.GetPath());

  wxDateTime t = name.GetModificationTime();
  if( t.IsValid() )
    return t.FormatDate()+" "+t.FormatTime();
  else
    return wxEmptyString;
}


wxString FitsMeta::GetKeys(const wxString& key) const
{
  //  if( type == FITS_COLOR )
  //    return hdu[1].GetKey(key);

  wxString a;
  for(size_t k = 0; k < hdu.size(); k++) {
    wxString l = hdu[k].GetKey(key);
    if( a.IsEmpty() )
      a = l;
    else
      a += "," + l;
  }
  return a;
}

wxString FitsMeta::GetDateobs(const wxString& key) const
{
  wxString a(GetKeys(key));
  a.Replace("T"," ");
  wxLogDebug(key+": "+a);
  return a;
}

wxString FitsMeta::GetFilter(const wxString& key) const
{
  return type == FITS_COLOUR ? "RGB" : GetKeys(key);
}

wxString FitsMeta::GetExposure(const wxString& key) const
{

  wxString l(GetKeys(key));
  double x;

  if( ! l.IsEmpty() && l.ToDouble(&x)) {
    wxString line;
    line.Printf("%g",x);
    return line;
  }
  else
    return l;
}

wxString FitsMeta::GetURL() const
{
  return url;
}

void FitsMeta::SetURL(const wxString& a)
{
  url = a;
}

bool FitsMeta::IsOk() const
{
  return ! url.IsEmpty();
}


wxString FitsMeta::GetName() const
{
  wxURI uri(url);
  wxFileName name(uri.GetPath());
  return name.GetName();
}

wxString FitsMeta::GetPath() const
{
  wxURI uri(url);
  wxFileName name(uri.GetPath());
  return name.GetPath();
}

wxString FitsMeta::GetFullPath() const
{
  wxURI uri(url);
  wxFileName name(uri.GetPath());
  return name.GetFullPath();
}

wxString FitsMeta::GetFullName() const
{
  wxURI uri(url);
  wxFileName name(uri.GetPath());
  return name.GetFullName();
}

wxString FitsMeta::GetHumanReadableSize() const
{
  return wxFileName::GetHumanReadableSize(size);
}


wxULongLong FitsMeta::GetSize() const
{
  return size;
}

void FitsMeta::Clear()
{
  url.Clear();
  type_str.Clear();
  type = FITS_UNKNOWN;
  hdu.clear();
  icon = xEmptyImage();
  size = wxInvalidSize;
}
