//=-- ThemeManager.cpp - Provides a context to load user themes from ---------=
//
//  The ThemeManager class provides a context for loading themes and other 
//    input files.  If AllowUserThemes is true, then this class first searches
//    the user's local theme directory for the file.  If it is not found there
//    or if AllowUserThemes is false, then the ServerResourcesPath is checked.
//    If the file is not found there either, then an empty string is returned.
//
//=---------------------------------------------------------------------------=
//  This file is copyright (c) 1997-2000 Chris Lattner
//=---------------------------------------------------------------------------=

#include "ThemeManager.h"
#include "MSFilename.h"
#include "Table.h"
#include "PlatformAbstraction.h"

#include <sys/types.h>       // Needed for sys/stat.h
#include <sys/stat.h>        // stat

ThemeManager::ThemeManager() { 
  AllowUserThemes = 1; 
  ResourcesSearched = new LinkedList<String>();
  ThemesFound = new Table<CSString, DataPair<String,String> >();
}

ThemeManager::~ThemeManager() { 
  delete ResourcesSearched;
  delete ThemesFound;
}

void ThemeManager::PrintThemes() {
  Table<CSString, DataPair<String,String> >::Iterator I = ThemesFound->GetStart();

  while (I) {
    cout << endl       << I->GetPrimary() << " Theme:\n";
    cout << "  Path: " << I->GetSecondary().GetPrimary()   << endl;
    cout << "  URL:  " << I->GetSecondary().GetSecondary() << endl;

    I++;
  }
}

int ThemeManager::AddThemeSourcePath(const String &ResPath, 
                                      const String &ResURL, 
                                      int ServerTheme) {
  String ThemeName;
  
  if (!ServerTheme && !AllowUserThemes) {
    return 1;
  } else if (ResPath.Length() == 0 || ResURL.Length() == 0) {
    return 1;
  } else {                  // See if we have already searched this directory.
    String Test(ResPath+ResURL);
    if (ResourcesSearched->SearchList(Test)) 
      return 0;  // Already searched this directory.

    ResourcesSearched->AddToHead(Test);  // Keep track for next time.
  }

  LinkedList<String> ThemesAvailable;
  MSFilename Dir = ResPath+"/Themes";

  if (PlatformAbstraction::ScanDirectory(Dir, ThemesAvailable, 
      PlatformAbstraction::Directory))
    return 1;      // No themes in resource directory.

  while (ThemesAvailable.GetLength() > 0) {
    struct stat StatBuf;
    ThemeName = ThemesAvailable.GetHead()->Data;
    MSFilename Filename = Dir + "/" + ThemeName + "/" + ThemeName + ".cfg";

    // Check to see the file exists and find out what type it is...
    int Status = stat(Filename, &StatBuf);
    
    // If the file exists and is a regular file... add it!
    if ((Status == 0) && (StatBuf.st_mode & S_IFREG)) 
      (*ThemesFound)[ThemeName] = DataPair<String, String>(Filename, ResURL);

    ThemesAvailable.RemoveHead();
  }

  return 0;
}

// FindTheme - Searches the user and server paths and returns the filename 
//   of the theme.  If the theme isn't found, an nonzero value is returned.
//
int ThemeManager::FindTheme(const String &ThemeName,
                            String &ReturnPath, String &ReturnURL) {
  MSFilename CheckPath, CheckFilename;

  if (!ThemesFound->InTable(ThemeName)) 
    return 1;

  DataPair<String, String> Theme((*ThemesFound)[ThemeName]);
  ReturnPath = Theme.GetPrimary();
  ReturnURL  = Theme.GetSecondary() + "/Themes/" + ThemeName + "/";
  return 0;
}
