#include <stdio.h>
#include <string.h>
#include "global.h"
#include "mode.h"
#include "window.h"

extern win_ptr gwin;
static major_mode mode_list = NULL;
static win_mode win_mode_list = NULL;

/* ----------------------------------------------------------------------- */
major_mode lookup_mode(char *mode)
{
  major_mode walk;
  for (walk = mode_list; walk; walk = walk->next)
    if (strcasecmp(walk->major_mode_name, mode) == 0)
      return walk;
  return NULL;
}

/* ----------------------------------------------------------------------- */
win_mode lookup_win_mode(char *mode)
{
  win_mode walk;
  for (walk = win_mode_list; walk; walk = walk->next)
    if (strcasecmp(walk->overall_name, mode) == 0)
      return walk;
  return NULL;
}

/* ----------------------------------------------------------------------- */
static win_mode_ptr create_win_mode_ptr(major_mode init_mode)
{
  win_mode_ptr tmp;
  tmp = (win_mode_ptr)mymalloc(sizeof(struct mm_list_struct));
  if (!tmp)
  {
    yell("fail to malloc for mode list in create of new win mode list");
    return NULL;
  }
  tmp->this_mode = init_mode;
  tmp->next = NULL;
  return tmp;
}

/* ----------------------------------------------------------------------- */
static win_mode create_win_mode(char *name, major_mode init)
{
  win_mode tmp;
  win_mode_ptr tmp2;
  tmp = (win_mode)mymalloc(sizeof(struct win_mode_master_list_struct));
  if (!tmp) {
    say("*** malloc for create_win_mode header failed");
    return NULL;
  }
  if (!(tmp->overall_name = m_strcpy(name)))
  {
    yell("malloc failed in create of win mode");
    myfree(tmp);
    return NULL;
  }
  if (!(tmp2 = create_win_mode_ptr(init)))
  {
    yell("*** Unable to create win_mode_ptr for new win_mode");
    myfree(tmp->overall_name);
    myfree(tmp);
    return NULL;
  }
  tmp->next = win_mode_list;
  tmp->modes = tmp2;
  tmp->default_mode = init;
  win_mode_list = tmp;
  return tmp;
}

/* ----------------------------------------------------------------------- */
win_mode set_major_mode(char *mode)
{
  major_mode ll;
  win_mode wm;
  if (!mode || !*mode)
  {
    curr_mode = NULL;
    return NULL;
  }
  wm = lookup_win_mode(mode);
  if (!wm)
  {
    say("*** Window mode does not exist, attempting to create it");
    ll = lookup_mode(mode);
    if (ll) wm = create_win_mode(mode, ll);
    else say("*** No such matching mode: %s", mode);
  }
  if (wm) {
    win_setmode(gwin, wm);
    return wm;
  }
  say("*** Could not find or create mode %s", mode);
  return NULL;
}

/* ----------------------------------------------------------------------- */
/* This routine is used to create a new major mode */
major_mode create_mode(char *mode)
{
  major_mode newmode;
  if ((newmode = lookup_mode(mode)))
  {
    say("*** MODE %s already exists", mode);
    return newmode;
  }
  newmode = (major_mode)mymalloc(sizeof(struct mm_struct));
  if (!newmode)
    say("*** Unable to allocate space for new mode");
  else
  {
    memset(newmode, 0, sizeof(struct mm_struct));
    if (!(newmode->major_mode_name = m_strcpy(mode)))
    {
      say("*** Unable to allocate space for name of new mode");
      myfree(newmode);
      newmode = NULL;
    }
    newmode->next = mode_list;
    mode_list = newmode;
    say("*** MODE %s created", mode);
  }
  return newmode;
}

/* ----------------------------------------------------------------------- */
void del_mode_to_mode(char *new)
{
  major_mode mm;
  win_mode wm;
  win_mode_ptr walk, back;
  wm = win_getmode(gwin);
  mm = lookup_mode(new);
  if (wm && mm)
    for (back = NULL, walk = wm->modes; walk; back = walk, walk = walk->next)
      if (walk->this_mode == mm)
      {
         if (back) back->next = walk->next;
         else wm->modes = walk->next;
         myfree(walk);
         say("*** MODE %s deleted from window mode list", new);
         return;
      }
  say("*** MODE %s could not be found in window mode list", new);
}
/* ----------------------------------------------------------------------- */
void add_mode_to_mode(char *new, int as_default)
{
  major_mode lu = lookup_mode(new);
  win_mode cwinm;
  win_mode_ptr tmp;
  cwinm = win_getmode(gwin);
  if (!cwinm)
  {
    cwinm = set_major_mode(new);
    if (as_default && cwinm) cwinm->default_mode = lu;
    if (!cwinm)
      yell("*** Unable to add new mode to current list");
    else
      yell("*** MODE %s added", new);
    return;
  }
  if (!lu) {
    yell("*** mode to add [%s] not found", new);
    return;
  }
  if (!(tmp = create_win_mode_ptr(lu)))
  {
    yell("*** unable to add new mode [%s] to list", new);
    return;
  }
  tmp->next = cwinm->modes;
  cwinm->modes = tmp;
  if (as_default) cwinm->default_mode = lu;
  say("*** MODE %s added", new);
}
