/* pcdl.c - Function dealing with the Phone Category Language
 *
 * This file is part of TUA.
 *
 *   Copyright (C) 1991,96  Lele Gaifax
 *
 *   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */

#include "tua.h"
#include "pcdl.h"

extern void EXFUN(yyerror, (CONST char * s));	  

static CONST char *
DEFUN(slot_to_string, (slot),
      CONST pcdl_slots * CONST slot)
{
  static char buffer[sizeof "10:30-12:11"];
  int h1, m1;
  int h2, m2;

  h1 = slot->from / 60;
  m1 = slot->from % 60;
  h2 = slot->to / 60;
  m2 = slot->to % 60;
  sprintf (buffer, "%02d:%02d-%02d:%02d", h1, m1, h2, m2);
  return buffer;
}
  
static CONST char * CONST days[] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" };

/* Print COUNTRY in format compatible with ourself. */
void
DEFUN(pcdl_print_country, (country),
      CONST pcdl_country * CONST country)
{
  CONST pcdl_names * nl = country->names;
  CONST pcdl_slots * sl;
  int day;
  
  printf ("country \"%s\" = {\n", country->name);

  if (country->currency)
    printf ("\tcurrency = \"%s\";\n", country->currency);

  printf ("\tdecimals = %hd;\n", country->decimals);
  
  while (nl)
    {
      printf ("\tname %c = \"%s\";\n", nl->cost+'@', nl->name);
      if (nl->cost_per_unit)
	{
	  if (nl->call_cost)
	    printf ("\tconst %c = %g,%g/%g;\n", nl->cost+'@', nl->call_cost, nl->cost_per_unit, nl->seconds_per_unit);
	  else
	    printf ("\tcost %c = %g/%g;\n", nl->cost+'@', nl->cost_per_unit, nl->seconds_per_unit);
	}
      
      nl = nl->next;
    }
  
  for (day=0; day<7; day++)
    {
      printf ("\t%s = {\n", days[day]);
      sl = country->slots[day];
      while (sl)
	{
	  printf ("\t  rate %c = %s;\n", sl->cost+'@', slot_to_string (sl));
	  sl = sl->next;
	}
      printf ("\t};\n");
    }
  
  printf ("}\n");
}

/* Returns TRUE if SLOT1 overlaps SLOT2 */
static int
DEFUN(slots_overlaps, (slot1, slot2),
      CONST pcdl_slots * CONST slot1 AND
      CONST pcdl_slots * CONST slot2)
{
  if ((slot1->from >= slot2->from && slot1->from <= slot2->to) ||
      (slot1->to >= slot2->from && slot1->to <= slot2->to))
    return TRUE;
  else
    return FALSE;
}

/* Insert a copy of SLOT in SLOT_LIST, checking for possible overlapping
 * slots. If such slots exist, do not insert them in the list. */
pcdl_slots *
DEFUN(pcdl_insert_slot, (slot, slot_list),
      pcdl_slots * slot AND pcdl_slots * slot_list)
{
  if (slot_list)
    {
      pcdl_slots * node = slot_list;
      pcdl_slots * prev = 0;
            
      while (node->from < slot->from && node->next)
	{
	  prev = node;
	  node = node->next;
	}

      if (slots_overlaps (node, slot))
	{
	  yyerror (_("overlapping slots: "));
	  fprintf (stderr, _("{ rate %d, %s at line %d } and "),
		   node->cost, slot_to_string (node), node->definition_line);
	  fprintf (stderr, _("{ rate %d, %s at line %d }\n"),
		   slot->cost, slot_to_string (slot), slot->definition_line);
	}
      else if (prev && slots_overlaps (prev, slot))
	{
	  extern void EXFUN(yyerror, (CONST char * s));
	  
	  yyerror (_("overlapping slots: "));
	  fprintf (stderr, _("{ rate %d, %s at line %d } and "),
		   prev->cost, slot_to_string (prev), prev->definition_line);
	  fprintf (stderr, _("{ rate %d, %s at line %d }\n"),
		   slot->cost, slot_to_string (slot), slot->definition_line);
	}
      else
	{
	  pcdl_slots * new = pcdl_create_new_slot();

	  *new = *slot;
	  new->next = 0;
	  
	  if (node->from < new->from)
	    {
	      new->next = node->next;
	      node->next = new;
	    }
	  else
	    {
	      new->next = node;
	      if (prev)
		prev->next = new;
	      else
		slot_list = new;
	    }
	}
    }
  else
    {
      pcdl_slots * new = pcdl_create_new_slot();
      
      *new = *slot;
      new->next = 0;
      
      slot_list = new;
    }

  return slot_list;
}
  
pcdl_slots *
DEFUN_VOID (pcdl_create_new_slot)
{
  pcdl_slots * new = (pcdl_slots *) xmalloc (sizeof (pcdl_slots));

  new->next = 0;
  return new;
}

pcdl_slots *
DEFUN(pcdl_merge_slots, (list1, list2),
      pcdl_slots * list1 AND pcdl_slots * list2)
{
  pcdl_slots * result = list1;

  while (list2)
    {
      result = pcdl_insert_slot (list2, result);

      list2 = list2->next;
    }

  return result;
}

pcdl_names *
DEFUN(pcdl_insert_name, (name, name_list),
      pcdl_names * name AND pcdl_names * name_list)
{
  if (name_list)
    {
      pcdl_names * node = name_list;

      while (node->cost < name->cost && node->next)
	node = node->next;

      if (node->cost == name->cost)
	{
	  extern void EXFUN(yyerror, (CONST char * s));

	  yyerror (_("overlapping costs!"));
	}
      else if (node->cost < name->cost)
	{
	  node->next = name;
	}
      else
	{
	  name->next = name_list;
	  name_list = name;
	}
    }
  else
    name_list = name;
  
  return name_list;
}
  
pcdl_names *
DEFUN_VOID (pcdl_create_new_name)
{
  pcdl_names * new = (pcdl_names *) xmalloc (sizeof (pcdl_names));

  new->seconds_per_unit = new->call_cost = new->cost_per_unit = 0.0;
  new->next = 0;
  return new;
}

CONST char * default_country_name = 0;

CONST char *
DEFUN (pcd_rate_name, (rate),
       int rate)
{
  pcdl_names * nl = current_country.names;
  
  for (nl = current_country.names; nl && nl->cost != rate; nl = nl->next)
    ;

  return nl->name;
}

float
DEFUN (pcd_rate_call_cost, (rate),
       int rate)
{
  pcdl_names * nl = current_country.names;
  
  for (nl = current_country.names; nl && nl->cost != rate; nl = nl->next)
    ;

  return nl->call_cost;
}

float
DEFUN (pcd_calculate_cost, (rate, secs),
       int rate AND float secs)
{
  pcdl_names * nl = current_country.names;
  
  for (nl = current_country.names; nl && nl->cost != rate; nl = nl->next)
    ;

  if (nl && nl->seconds_per_unit)
    {
      int units = secs / nl->seconds_per_unit + 1;

      return units * nl->cost_per_unit;
    }
  else
    return 0.0;
}

static pcdl_names * symbol_list = 0;

int
DEFUN (pcdl_lookup_rate_symbol, (symbol, ins_flag),
       CONST char * symbol AND int ins_flag)
{
  if (symbol_list)
    {
      pcdl_names * sl = symbol_list;
      
      while (1)
	{
	  if (strcmp (symbol, sl->name) == 0)
	    return sl->cost;

	  if (sl->next == 0)
	    break;
	  else
	    sl = sl->next;
	}

      if (ins_flag)
	{
	  pcdl_names * n = pcdl_create_new_name ();

	  n->name = savestring (symbol);
	  n->cost = sl->cost+1;
	  n->next = 0;
	  sl->next = n;
	  return n->cost;
	}
      else
	{
	  yyerror(_("Rate symbol "));
	  fprintf (stderr, _("%s not yet defined!\n"), symbol);
	  exit(1);
	}
    }
  else
    {
      pcdl_names * n = pcdl_create_new_name();
      
      n->name = savestring (symbol);
      n->cost = 1;
      n->next = 0;
      symbol_list = n;
      return 1;
    }
}
  
void
DEFUN_VOID (pcdl_destroy_symbol_list)
{
  while (symbol_list)
    {
      pcdl_names * n = symbol_list;
      pcdl_names * next = n->next;
      
      xfree (n->name);
      xfree (n);
      
      symbol_list = next;
    }
}
