/* -*- mia-c++  -*-
 *
 * This file is part of MIA - a toolbox for medical image analysis
 * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
 *
 * MIA 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.
 *
 * This program 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 MIA; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <sstream>
#include <cstring>
#include <climits>

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp> // includes boost/filesystem/path.hpp
#include <boost/filesystem/fstream.hpp>    // ditto

#include <mia/core/msgstream.hh>
#include <mia/core/filetools.hh>

#ifdef WIN32
#define snprintf _snprintf
#define strdup _strdup
#endif

NS_MIA_BEGIN

using namespace std;
using namespace mia;


namespace bfs = ::boost::filesystem;

#ifndef MAX_PATH
#define MAX_PATH 4096
#endif

EXPORT_CORE const std::string get_filename_pattern_and_range(std::string const& in_filename,
              size_t& start_filenum,
              size_t& end_filenum, size_t& format_width)
{
       string base_name;
       size_t nwidth = format_width = fname_to_cformat(in_filename.c_str(), base_name, false);

       if (nwidth > 0) { // probably more then one slice
              size_t max_num = 1;

              while (nwidth--)
                     max_num *= 10;

              start_filenum = end_filenum = 0;
              cvdebug() << "trying files of pattern " << base_name << " n=" << nwidth << "\n";
              // search for the first existing file
              string filename = create_filename(base_name.c_str(), start_filenum);

              while (!bfs::exists(filename) && start_filenum < max_num) {
                     ++start_filenum;
                     filename = create_filename(base_name.c_str(), start_filenum);
              }

              end_filenum = start_filenum;

              while (bfs::exists(filename) &&  end_filenum < max_num) {
                     ++end_filenum;
                     filename = create_filename(base_name.c_str(), end_filenum);

                     if (end_filenum == 0)
                            break;
              }
       }

       return base_name;
}


vector<string> get_consecutive_numbered_files(string const& in_filename)
{
       vector<string> src_names;
       string base_name;
       // get all possible file names
       size_t nwidth = fname_to_cformat(in_filename.c_str(), base_name, false);

       if (nwidth > 0) { // probably more then one slice
              // check, how many consecutive files we have
              int n_files = 0;
              size_t start_filenum = 0;
              cvdebug() << "trying files of pattern " << base_name << " n="
                        << nwidth << "\n";
              // search for the first existing file
              string filename = create_filename(base_name.c_str(), start_filenum);
              string first_filename = filename;
              size_t max_num = 1;

              while (nwidth--)
                     max_num *= 10;

              while (!bfs::exists(filename) && start_filenum < max_num) {
                     ++start_filenum;
                     filename = create_filename(base_name.c_str(), start_filenum);
              }

              while (bfs::exists(filename) &&  start_filenum < max_num) {
                     src_names.push_back(filename);
                     ++start_filenum;
                     ++n_files;
                     filename = create_filename(base_name.c_str(), start_filenum);

                     if (filename == src_names[0])
                            break;
              }

              cvdebug() << "Found " << n_files << " input files\n";
       } else {
              src_names.push_back(in_filename);
       }

       return src_names;
}

EXPORT_CORE size_t fname_to_cformat(const char *fname, string& base, bool wildcard)
{
       char *help = strdup(fname);
       char *suffix = strrchr(help, '.');

       if (suffix == help) {
              base.assign(fname);
              free(help);
              return 0;
       }

       char *num = suffix ? suffix : help + strlen(help);
       --num;
       size_t nwidth = 0;

       while (isdigit(*num)) 	{
              ++nwidth;

              if (num == help)
                     break;

              --num;
       }

       if (nwidth == 0) {
              base.assign(fname);
              free(help);
              return 0;
       }

       stringstream result;

       if (num != help) {
              num[1] = '\0'; // cut of the tail
              result << help;
       }

       if (wildcard) {
              for (size_t i = 0; i < nwidth; ++i)
                     result << "?";
       } else {
              result << "%0" << nwidth << "d";
       }

       if (suffix)
              result << suffix;

       base = result.str();
       free(help);
       return nwidth;
}


// ugly
EXPORT_CORE string create_filename(const char *cformat, size_t num)
{
       char buf[FILENAME_MAX];
       snprintf(buf, FILENAME_MAX, cformat, num);
       return string(buf);
}

EXPORT_CORE size_t get_filename_number_pattern_width(std::string const& in_filename)
{
       size_t n = 0;
       int  last_dot = in_filename.rfind('.');

       if (last_dot == 0)
              return n;

       string base = in_filename.substr(0, last_dot);
       string::reverse_iterator rit = base.rbegin();

       while (rit < base.rend() && isdigit(*rit)) {
              ++n;
              ++rit;
       }

       return n;
}

EXPORT_CORE size_t get_filename_number_pattern(std::string const& in_filename, string& base, string& suffix)
{
       bfs::path p(in_filename);
       suffix = p.extension().string();
       string rest = p.stem().string();
       size_t nwidth = 0;
       string::const_reverse_iterator r = rest.rbegin();

       while (isdigit(*r)) {
              ++r;
              ++nwidth;
       }

       base = rest.substr(0, rest.size() - nwidth);
       return nwidth;
}

EXPORT_CORE void split_filename_number_pattern(std::string const& in_filename, std::string& base,
              std::string& suffix, std::string& number)
{
       bfs::path p(in_filename);
       size_t nwidth = get_filename_number_pattern(in_filename, base, suffix);
       string stem = p.stem().string();
       number = stem.substr(stem.size() - nwidth);
}

NS_MIA_END
