// Copyright (c) 2012 by Zuse-Institute Berlin and the Technical University of Denmark.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     1. Redistributions of source code must retain the above copyright
//        notice, this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright
//        notice, this list of conditions and the following disclaimer in the
//        documentation and/or other materials provided with the distribution.
//     3. Neither the name of the copyright holders nor contributors may not
//        be used to endorse or promote products derived from this software
//        without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS NOR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "frontend-cbf.h"
#include "backend-cbf.h"
#include "backend-mps-mosek.h"
#include "backend-mps-cplex.h"
#include "backend-sdpa.h"

#include "cbf-data.h"
#include "sysconverter.h"

#include <stdio.h>
#include <string.h>

typedef enum CBFfilemanager_enum {
  CBF_FILEMAN_BEGIN = 0,
  CBF_FILEMAN_END = 4,      // Last plus one

  CBF_FILEMAN_CBF = 0,
  CBF_FILEMAN_MPS_MOSEK = 1,
  CBF_FILEMAN_MPS_CPLEX = 2,
  CBF_FILEMAN_SDPA = 3,
} CBFfilemanagere;

const char        *fileman_name[CBF_FILEMAN_END];
const char        *fileman_format[CBF_FILEMAN_END];
const CBFfrontend *fileman_frontend[CBF_FILEMAN_END];
const CBFbackend  *fileman_backend[CBF_FILEMAN_END];

static void init();

static CBFresponsee getoptions(int argc, char *argv[],
    const CBFfrontend **frontend,
    const CBFbackend **backend,
    const char **iformat,
    const char **oformat,
    const char **opath);


// -------------------------------------
// Function definitions
// -------------------------------------

int main (int argc, char *argv[])
{
  CBFresponsee res = CBF_RES_OK;
  const CBFfrontend *frontend;
  const CBFbackend  *backend;
  const char *iformat;
  const char *oformat;
  const char *opath;
  int i;

  // For debugging
  setbuf(stdout, NULL);

  init();
  res = getoptions(argc, argv, &frontend, &backend, &iformat, &oformat, &opath);

  if (argc < 2 || res != CBF_RES_OK)
  {
    printf("\nBad command, syntax is:\n");
    printf(">> cbftool [OPTIONS] infile1 infile2 infile3 ...\n\n");
    printf("OPTIONS:\n");
    printf("  -i format   : File manager for input files:\n");
    printf("                ");
    for (i=CBF_FILEMAN_BEGIN; i<CBF_FILEMAN_END; ++i) {
      if (i == CBF_FILEMAN_CBF)
        printf("(%s), ", fileman_name[i]);
      else if (fileman_frontend[i] != NULL)
        printf("%s, ", fileman_name[i]);
    }
    printf("\n");
    printf("  -o format   : File manager for output files:\n");
    printf("                ");
    for (i=CBF_FILEMAN_BEGIN; i<CBF_FILEMAN_END; ++i) {
      if (i == CBF_FILEMAN_CBF)
        printf("(%s), ", fileman_name[i]);
      else if (fileman_backend[i] != NULL)
        printf("%s, ", fileman_name[i]);
    }
    printf("\n");
    printf("  -opath path : Output destination.\n");
    printf("\n\n");
  }
  else
  {
    res = CBF_convertfiles(argc, argv, frontend, backend, iformat, oformat, opath);
  }

  return res;
}

static void init()
{
  int i;

  // Initiate to NULL
  for (i=CBF_FILEMAN_BEGIN; i<CBF_FILEMAN_END; ++i) {
    fileman_name    [i] = "";
    fileman_format  [i] = "";
    fileman_frontend[i] = NULL;
    fileman_backend [i] = NULL;
  }

  fileman_name    [CBF_FILEMAN_CBF] = "cbf";
  fileman_format  [CBF_FILEMAN_CBF] = "cbf";
  fileman_frontend[CBF_FILEMAN_CBF] = &frontend_cbf;
  fileman_backend [CBF_FILEMAN_CBF] = &backend_cbf;

  fileman_name    [CBF_FILEMAN_MPS_MOSEK] = "mps-mosek";
  fileman_format  [CBF_FILEMAN_MPS_MOSEK] = "mps";
  fileman_frontend[CBF_FILEMAN_MPS_MOSEK] = NULL;
  fileman_backend [CBF_FILEMAN_MPS_MOSEK] = &backend_mps_mosek;

  fileman_name    [CBF_FILEMAN_MPS_CPLEX] = "mps-cplex";
  fileman_format  [CBF_FILEMAN_MPS_CPLEX] = "mps";
  fileman_frontend[CBF_FILEMAN_MPS_CPLEX] = NULL;
  fileman_backend [CBF_FILEMAN_MPS_CPLEX] = &backend_mps_cplex;

  fileman_name    [CBF_FILEMAN_SDPA] = "sdpa";
  fileman_format  [CBF_FILEMAN_SDPA] = "dat-s";
  fileman_frontend[CBF_FILEMAN_SDPA] = NULL;
  fileman_backend [CBF_FILEMAN_SDPA] = &backend_sdpa;
}

static CBFresponsee getoptions(int argc, char *argv[],
    const CBFfrontend **frontend,
    const CBFbackend **backend,
    const char **iformat,
    const char **oformat,
    const char **opath)
{
  CBFresponsee res = CBF_RES_OK;
  char *ifileman = "cbf";
  char *ofileman = "cbf";
  int i;

  *frontend = NULL;
  *backend = NULL;
  *iformat = NULL;
  *oformat = NULL;
  *opath = NULL;

  // Find ifileman and ofileman
  for (i=1; i<argc && res==CBF_RES_OK; ++i) {
    if (argv[i]) {

      if (strcmp(argv[i], "-i") == 0) {
        if (i+1<argc) {
          ifileman = argv[i+1];
          argv[i] = NULL;
          argv[i+1] = NULL;
        } else {
          res = CBF_RES_ERR;
        }
      }

      else if (strcmp(argv[i], "-o") == 0) {
        if (i+1<argc) {
          ofileman = argv[i+1];
          argv[i] = NULL;
          argv[i+1] = NULL;
        } else {
          res = CBF_RES_ERR;
        }
      }

      else if (strcmp(argv[i], "-opath") == 0) {
        if (i+1<argc) {
          *opath = argv[i+1];
          argv[i] = NULL;
          argv[i+1] = NULL;
        } else {
          res = CBF_RES_ERR;
        }
      }
    }
  }

  if ( res==CBF_RES_OK )
  {
    // Map ifileman to a frontend and file format
    for (i=0; i<CBF_FILEMAN_END; ++i) {
      if (strcmp(ifileman, fileman_name[i]) == 0) {
        *frontend = fileman_frontend[i];
        *iformat = fileman_format[i];
        break;
      }
    }

    // Map ofileman to a backend and file format
    for (i=0; i<CBF_FILEMAN_END; ++i) {
      if (strcmp(ofileman, fileman_name[i]) == 0) {
        *backend = fileman_backend[i];
        *oformat = fileman_format[i];
        break;
      }
    }

    if (*frontend == NULL || *backend == NULL || *iformat == NULL || *oformat == NULL)
      res = CBF_RES_ERR;
  }

  return res;
}
