/*

  Munipack - command line interface

  Copyright © 2012-3, 2018-9 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 "munipack.h"
#include "fitsfn.h"
#include <wx/wx.h>
#include <wx/cmdline.h>
#include <wx/regex.h>
#include <wx/tokenzr.h>
#include <wx/filename.h>
#include <wx/file.h>
#include <wx/stream.h>
#include <wx/sstream.h>


void Munipack::CommonOutputSingle(MuniProcess *action, const MuniCmdLineParser&
				  cmd, const wxString& name)
{
  wxString a;

  if( cmd.Found("verbose") )
    action->Write("VERBOSE = T");

  wxString output;
  if( cmd.Found("output",&a) || cmd.Found("o",&a) )
    output = a;
  else if( name != "" )
    output = name + ".fits";
  else
    output = action->GetCommand() + ".fits";

  WriteOutput(action,output);
}

void Munipack::CommonOutputMultiple(MuniProcess *action,
				    const MuniCmdLineParser& cmd)
{
  wxString a;

  if( cmd.Found("verbose") )
    action->Write("VERBOSE = T");

  if( cmd.Found("target-directory",&a) || cmd.Found("t",&a) ) {
    if( ! SetTargetDir(a) )
      wxLogFatalError("Directory `"+target+"' does not exists.");
  }

  if( cmd.Found("O") || cmd.Found("mask",&a) ) {

    SetAdvanced(true);

    if( cmd.Found("pattern",&a) )
      SetPattern(a);

    if( cmd.Found("mask",&a) )
      SetMask(a);

    if( cmd.Found("format",&a) )
      SetFormat(a);
  }
}

void Munipack::CommonOptionsBitpix(MuniProcess *action,
				   const MuniCmdLineParser& cmd)
{
  long n;
  if( cmd.Found("bitpix",&n) || cmd.Found("B",&n) )
    action->Write("BITPIX = %ld",n);
}

void Munipack::CommonOptionsEnableOverwrite(MuniProcess *action,
					    const MuniCmdLineParser& cmd)
{
  if( cmd.Found("enable-overwrite") )
    action->Write("OVERWRITE = T");
}

void Munipack::CommonOptionsPhCorr(MuniProcess *action,
				   const MuniCmdLineParser& cmd)
{
  wxString a;
  double x;

  // command line options
  if( cmd.Found("bitmask",&a) )
    action->Write("MASK = '"+a+"'");

  if( cmd.Found("st",&x) || cmd.Found("saturate",&x) )
    action->Write("SATURATE = %lf",x);

  if( cmd.Found("th",&x) || cmd.Found("threshold",&x) )
    action->Write("THRESHOLD = %lf",x);
}

void Munipack::EnvironmentPhCorr(MuniProcess *action)
{
  // environment variables
  const char *envvar[] = {
    "MUNIPACK_TEMPERATURE_TOLERANCE",
    "MUNIPACK_EXPTIME_TOLERANCE",
    0
  };

  for(size_t i = 0; envvar[i] != 0; i++) {
    wxString val, var(envvar[i]);
    double x;
    if( wxGetEnv(var,&val) && val.ToDouble(&x) )   // for numbers
      action->Write(var + " = %.1le",x);
  }
}

void Munipack::CommonOptionsPhq(MuniProcess *action,
				const MuniCmdLineParser& cmd)
{
  wxString a;

  if( cmd.Found("q",&a) || cmd.Found("quantity",&a) ) {

    wxString l;
    long n;

    apstr(a,n,l);
    action->Write("NQUANTITIES = %d",n);
    action->Write("QUANTITIES = " + l);
  }
}

void Munipack::WriteOutput(MuniProcess *action, const wxString& output) const
{
  wxASSERT(output != "");
  action->Write("OUTPUT = '" + output + "' ");
}

void Munipack::WriteFiles(MuniProcess *action,
			  const MuniCmdLineParser& cmd) const
{
  action->Write("NFILES = %d",static_cast<int>(cmd.GetFilesCount()));

  for(size_t n = 0; n < cmd.GetFilesCount(); n++) {

    wxString line = cmd.GetFile(n);

    // splits input 'line' by filenames: source [target]
    // filenames with spaces are taken on more pieces than expected.
    wxArrayString filenames;
    wxStringTokenizer tokenizer(line);
    while ( tokenizer.HasMoreTokens() ) {
      wxString name = tokenizer.GetNextToken();
      filenames.push_back(name);
    }

    wxString filename, output;

    if( filenames.size() == 1 ) {
      filename = filenames[0];
      if( advanced ) {
	if( format == "" )
	  output = GetAdvanced(filename);
	else
	  output = GetFormat(n);
      }
      else
	output = GetOutput(filename);
    }
    else if( filenames.size() == 2 ) {
      filename = filenames[0];
      output = filenames[1];
    }
    else
      wxLogFatalError("Format of input file: source-file [target-file]");

    action->Write("FILE = '" + filename + "' '" + output + "'");
  }
}


void Munipack::WriteFiles(MuniProcess *action,
			  const wxArrayString& files) const
{
  action->Write("NFILES = %d",static_cast<int>(files.size()));
  for(size_t n = 0; n < files.size(); n++)
    action->Write("FILE = '" + files[n] + "'");
}

void Munipack::WriteFile(MuniProcess *action, const wxString& file) const
{
  wxArrayString files;
  files.push_back(file);
  WriteFiles(action,files);
}


void Munipack::apstr(const wxString& a, long& n, wxString& l)
{
  n = 0;
  l = "";

  wxStringTokenizer tokenizer(a,",");
  while( tokenizer.HasMoreTokens() ) {
    l += " '"+tokenizer.GetNextToken()+"'";
    n++;
  }
}

void Munipack::dblstr(const wxString& a, const wxString &sep,
		      long& n, wxString& l)
{
  n = 0;
  l = "";

  wxStringTokenizer objtokenizer(a,sep);
  while( objtokenizer.HasMoreTokens() ) {
    wxString c(objtokenizer.GetNextToken());
    double b;
    if( c.ToDouble(&b) ) {
      l += " " + c;
      n++;
    }
    else {
      wxLogFatalError("Failed to interpret `"+c+"' as a numerical value.");
      return;
    }
  }
}



// -----

wxString Munipack::GetAdvanced(const wxString& filename) const
{
  if( ! advanced ) return "";

  FITSFileName fitsfile(filename);
  wxString fullname = fitsfile.GetFullName();
  wxString output;

  if( mask == "" )
    wxLogFatalError("Regular expression mask is empty.");

  wxRegEx rf(pattern);
  if( ! rf.IsValid() )
    wxLogFatalError("Regular expression pattern `"+pattern+"' is invalid.");

  if( rf.Matches(filename) ) {

    output = fullname;
    int e = rf.Replace(&output,mask);
    if( e == -1 )
      wxLogFatalError("Regular expression `"+mask+"'failed to replace.");
    if( e == 0 )
      wxLogWarning("No replace for regular expression mask: `"+mask+"'.");
  }
  else
    wxLogFatalError("Regular expression has no match.");

  return output;
}

wxString Munipack::GetOutput(const wxString& name) const
{
  FITSFileName ftname(name);
  wxString filename(ftname.GetFullName());

  if( target == "" )
    return filename;
  else {
    wxFileName src(filename);
    wxFileName dest(target,src.GetFullName());
    return dest.GetFullPath();
  }
}

wxString Munipack::GetFormat(size_t n) const
{
  wxASSERT(format != "");

  wxString output;
  output.Printf(format,static_cast<int>(n));
  return output;
}


bool Munipack::SetTargetDir(const wxString& t)
{
  target = t;

  // check existence of the target directory
  wxFileName d;
  d.AssignDir(target);
  if( d.DirExists() )
    return true;
  else
    return false;
}
