/**************************************************************************

    This file is part of Xclass95, a Win95-looking GUI toolkit.
    Copyright (C) 1996, 1997 David Barth, Hector Peraza.

    This program 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 2 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 this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

**************************************************************************/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <limits.h>
#include <assert.h>
#include <regex.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <xclass/utils.h>
#include <xclass/OIniFile.h>
#include <xclass/OMimeTypes.h>


OMimeTypes::OMimeTypes(OXClient *client, const char *filename) {

  char     line[1024];
  char     mime[1024];
  char     pattern[256];
  char     icon[256];
  char     action[256];
  char    *tmppattern;
  char    *description;
  OIniFile myfile(filename, INI_READ);

  list = new OMime;
  list->next = NULL;
  listptr = list;
  _clientX = client;
  strcpy(_filename, filename);

  while (myfile.GetNext(line)) {
    strcpy(mime, line);
    myfile.GetItem("pattern", pattern);
    myfile.GetItem("icon", icon);
    myfile.GetItem("action", action);
    description = myfile.GetItem("description", NULL);
    if (strchr(pattern, ' ') != NULL) {
      tmppattern = strtok(pattern, " ");
      while (tmppattern && (*tmppattern != ' ')) {
        AddType(description, mime, (const char *) tmppattern, icon, action);
        tmppattern = strtok(NULL, " ");
      }
    } else {
      AddType(description, mime, pattern, icon, action);
    }
  }
  _changed = False;
}

OMimeTypes::~OMimeTypes() {
  OMime *nextptr;

  if (_changed) SaveMimes();
  listptr = list->next;
  while (listptr) {
    nextptr = listptr->next;
    if (listptr->description) delete[] listptr->description;
    delete listptr;
    listptr = nextptr;
  }
}

OMime *OMimeTypes::_Find(const char *filename) {

  regmatch_t   pmatch[1];
  size_t       nmatch = 1;

  listptr = list->next;
  if (filename) {
    while (listptr) {
      if (regexec(&listptr->preg, filename, nmatch, pmatch, 0) == 0) {
        if ((pmatch[0].rm_so == 0) && 
            (pmatch[0].rm_eo == strlen(filename))) {
          return listptr;
        }
      }
      listptr = listptr->next;
    }
  }
  return NULL;
}

const OPicture *OMimeTypes::GetIcon(OMime *mime, int small_icon) {
  return (small_icon) ?  
      _clientX->GetPicture(mime->icon, 16, 16) : 
      _clientX->GetPicture(mime->icon, 32, 32);
}

const OPicture *OMimeTypes::GetIcon(const char *filename, int small_icon) {

  const OPicture  *mypic;

  if (_Find(filename)) {
    if (small_icon)
      mypic = _clientX->GetPicture(listptr->icon, 16, 16);
    else
      mypic = _clientX->GetPicture(listptr->icon, 32, 32);
    return mypic;
  }
  return NULL;
}

int OMimeTypes::GetAction(const char *filename, char *action) {

  *action = '\0';
  if (_Find(filename)) {
    strcpy(action, listptr->action);
    return (strlen(action) > 0);
  }
  return 0;
}

int OMimeTypes::GetType(const char *filename, char *type) {

  *type = '\0';
  if (_Find(filename)) {
    strcpy(type, listptr->type);
    return (strlen(type) > 0);
  }
  return 0;
}

char *OMimeTypes::GetDescription(const char *filename) {
  if (_Find(filename))
    return listptr->description;
  return NULL;
}

void OMimeTypes::PrintTypes() {

  listptr = list->next;

  while (listptr) {
    printf("Description: %s\n", listptr->description ? "" : listptr->description);
    printf("Type: %s\n", listptr->type);
    printf("Pattern: %s\n", listptr->pattern);
    printf("Action: %s\n", listptr->action);
    printf("------------\n\n");
    listptr = listptr->next;
  }
}

void OMimeTypes::SaveMimes() {

  OMime    *tmpptr;
  OIniFile  myfile(_filename, INI_WRITE);
  
  tmpptr = listptr;
  listptr = list->next;
  while (listptr) {
    myfile.PutNext(listptr->type);
    if (listptr->description)
      myfile.PutItem("description", listptr->description);
    myfile.PutItem("pattern", listptr->pattern);
    myfile.PutItem("icon", listptr->icon);
    myfile.PutItem("action", listptr->action);
    myfile.PutNewLine();
    listptr = listptr->next;
  }
  listptr = tmpptr;
  _changed = False;
}

void OMimeTypes::AddType(char *description,
                   const char *type, 
		   const char *pattern,
		   const char *icon,
		   const char *action) {

  OMime      *tmpmime;
  char        expression[50];
  int         pos = 0;
  const char *ptr = NULL;

  tmpmime = new OMime;

  listptr->next = tmpmime;
  listptr = tmpmime;
  strcpy(listptr->type, type);
  strcpy(listptr->pattern, pattern);
  ptr = pattern;
  pos = 0;
  while (*ptr != '\0') {
    if (*ptr == '*')
      expression[pos++] = '.';
    else if (*ptr == '.')
      expression[pos++] = '\\';
    expression[pos++] = *ptr;
    ptr++;
  }
  expression[pos] = '\0';
  regcomp(&listptr->preg, expression, REG_EXTENDED);
  strcpy(listptr->action, action);
  strcpy(listptr->icon, icon);
  listptr->description = description;
  listptr->next = NULL;
  _changed = True;
}

OMime *OMimeTypes::NextMime(OMime *prev) {
  return (prev) ? prev->next : list->next;
}

void OMimeTypes::Modify(OMime *mime, 
                        char *description,
                        char *type, 
                        char *pattern,
                        char *icon,
                        char *action) {

  if (description) {
    if (mime->description) delete mime->description;
    mime->description = description;
  }

  if (type) strcpy(mime->type, type);
  if (action) strcpy(mime->action, action);
  if (icon) strcpy(mime->icon, icon);
  if (pattern) strcpy(mime->pattern, pattern);

  _changed = True;
}
