/*------------------------------------------------------------------------------
 src/lib/dj/appBase.cxx
 
 Copyright (c) 2004-2006 Darby Johnston.
 All rights reserved.
 Use is subject to license terms.
------------------------------------------------------------------------------*/

//#define DJ_DBG
#include "djAppBase.h"
#include <djDir.h>
#include <sys/ioctl.h>
#include <sys/termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

namespace dj {

AppBase * AppBase::_instance = 0;

AppBase::AppBase(const Str & name, int &, char ** argv) :
  _name(name),
  _terminalWidth(80),
  _exitValue(0),
  _printSeparator(false)
{
  DJ_DBG_FNC("dj::AppBase::AppBase");
  DJ_DBG_PRN("name = " << name);

  // Global application pointer.
  //
  _instance = this;
  
  // Information.
  //
  searchPathList(argv[0]);
  updateTerminalWidth();
}

AppBase::~AppBase()
{
  DJ_DBG_FNC("dj::AppBase::~AppBase");
}

void AppBase::about()
{
  printFormatted(Str("\n%1\n").arg(aboutStr()));
}

const Str AppBase::aboutStr() const
{
  static const char tmp [] =
    "DJV %1\n"
    "http://djv.sourceforge.net\n"
    "\n"
    "Copyright (c) 2004-2006 Darby Johnston.\n"
    "All rights reserved.\n"
    "Use is subject to license terms.\n"
    "\n"
    "Made in Berkeley, CA, USA.";
  return Str(tmp).arg(DJ_VERSION);
}

void AppBase::exitValue(int in)
{
  _exitValue = in;
}

void AppBase::error(const Str & in) const
{
  print(Str("ERROR: %1").arg(in));
}

void AppBase::print(const Str & in) const
{
  if (_printSeparator) {
    printf("\n");
    const_cast<AppBase *>(this)->_printSeparator = false;
  }
  printf("%s\n", in.toAscii());
}

void AppBase::printFormatted(const Str & in) const
{
  //print(Str(" ") + in);

  // Format input to a fixed line width with a one character border at the
  // beginning and end.
  //
  Str tmp = replace(in, '\n', Str("\n "));
  const int lineWidth = _terminalWidth;
  int charCount = 0, lastSpaceIndex = 0;
  for (int i = 0; i < tmp.size(); ++i, ++charCount) {  
    if (' ' == tmp[i]) lastSpaceIndex = i;
    else if ('\n' == tmp[i]) charCount = 0;  
    if (charCount >= (lineWidth - 2)) {
      tmp.replace(Str("\n "), lastSpaceIndex);
      charCount = 0;
      i = ++lastSpaceIndex;
    }
  }
  print(Str(" ") + tmp);
}

void AppBase::printSeparator() const
{
  const_cast<AppBase *>(this)->_printSeparator = true;
}

void AppBase::searchPathList(const Str & appName)
{
  DJ_DBG_FNC("dj::AppBase::searchPathList");
  DJ_DBG_PRN("app name = " << appName);
  
  // Installation path.
  //
  StrList tmp;
# ifdef DJ_SEARCH_PATH
  tmp = split(Str(DJ_SEARCH_PATH), ':');
  DJ_DBG_PRN("install = " << tmp);
  for (StrListIt it = tmp; it.isValid(); ++it)
    _searchPathList += it();
# endif

  // DJV_PATH environment variable.
  //
  Str env(getenv("DJV_PATH"));
  if (! env.isNull()) {
    tmp = split(env, ':');
    DJ_DBG_PRN("DJV_PATH = " << tmp);
    for (StrListIt it = tmp; it.isValid(); ++it)
      _searchPathList += it();
  }
  
  // Distribution path.
  //
  Str dist(appName);
  if (find(dist, '/') != -1) ;
  else {
    env = Str(getenv("PATH"));
    if (! env.isNull()) {
      tmp = split(env, ':');
      for (StrListIt it = tmp; it.isValid(); ++it) {
        DJ_DBG_PRN("path = " << it());
        Dir dir(it());
        const List<FileInfo> itemList =
          filter(dir.itemList(), FILE_FILTER_FILES);
        ConstListIt<FileInfo> it = itemList;
        for (; it.isValid(); ++it)
          if (dist == it().get(-1, false)) break;
        if (it.isValid()) {
          dist = it();
          break;
        }
      }
    }
  }
  tmp = dirPathFix(split(dist, '/'));
  DJ_DBG_PRN("dist = " << tmp);
  if (tmp.size() > 1) {
    tmp.shift();
    tmp.shift();
  }
  dist =
    ('/' == dist[0] ? Str("/") : Str()) +
    join(tmp, '/') +
    (tmp.size() ? Str("/") : Str());
  DJ_DBG_PRN("dist = " << dist);
  _searchPathList += dist + Str("lib");
  _searchPathList += dist + Str("plugin");
  
  DJ_DBG_PRN("search paths = " << _searchPathList);
}

void AppBase::updateTerminalWidth()
{
  DJ_DBG_FNC("dj::AppBase::updateTerminalWidth");

  struct winsize ws;
  ws.ws_col = 0;
  if (
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 &&
    ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1 &&
    ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1
  )
    ws.ws_col = 80;

  _terminalWidth = ws.ws_col;
  DJ_DBG_PRN("width = " << _terminalWidth);
}

}
