#include "standard.h"
#ifdef DISPATCHER

#include <stdlib.h>
#include "tdispatc.h"
#include "win_raw.h"
#include "tool.h"
#include "l_level.h"
#include "keyboard.h"
#include "vesa.h"
#include "tprint.h"
#include "error.h"
#include "button.h"
T_INT dispatcher_status=DISPATCHER_STARTING;
T_INT dispatcher_ebene=0;
T_INT dispatcher_type= ACTIVE_WINDOW | HIDE_LOWER_WINDOWS; //ACTIVE_WINDOW //FOCUS_WINDOW ACTIVE_ON_FOCUS

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

T_VOID dispatcher(T_VOID)
{
 typedef struct
 {
   T_INT i;
   T_INT key;
   T_INT action;
   WINDOW_LISTEN_ELEMENT *test_window_element;
   BUTTON_LISTEN_ELEMENT *test_button_element;
   PARAMETER parameter;
   T_LISTE *liste;
 }DISPATCHER_VARIABLEN;
 DISPATCHER_VARIABLEN *v;
 T_DEBUG_ENTRY("dispatcher",60)
 dispatcher_ebene++;
 v=(DISPATCHER_VARIABLEN *)malloc(sizeof(DISPATCHER_VARIABLEN));
 if (v==NULL)
 {
  T_DEBUG_FUNCTION_POSITION(1)
  T_DEBUG_LEAVE
  return;
 }
 if (dispatcher_type & HIDE_LOWER_WINDOWS)
  hide_lower_return_windows(dispatcher_ebene);
 while (dispatcher_status!=DISPATCHER_END)
 {
  vesa_mouse_update();
  dispatcher_status=DISPATCHER_WORKING;
  v->key=fKBDishit();
  v->action=T_FALSE;
  v->test_window_element=is_mouse_on_window();
  v->test_button_element=is_mouse_on_button(v->test_window_element);
  v->parameter.ebene=dispatcher_ebene;
  v->parameter.executed=PARAMETER_NOT_EXECUTED;
  v->parameter.taste=v->key;
  v->parameter.tastatur_status = 0; // obsolete
  v->parameter.maus_button=vesa_mouse_button;
  v->parameter.maus_x=vesa_mouse_x;
  v->parameter.maus_y=vesa_mouse_y;
  v->parameter.window_element=v->test_window_element;
  v->parameter.button_element=v->test_button_element;
  if (dispatcher_type&ACTIVATE_ON_FOCUS)
  {
   aktivate_window(v->test_window_element);
  }
/* erstmal nur auf buttons abfragen (wenn also eine Maustaste gedrueckt ist) */
  if (v->parameter.maus_button)
  {
   if (fKBDisLSHIFT()==T_TRUE)
    lower_window(v->test_window_element);
   else
   {
    if (fKBDisRSHIFT()==T_TRUE)
     aktivate_window(v->test_window_element);
   }
   if (v->test_button_element!=NULL)
   {
    if (v->test_button_element->button->schalt_art==SWITCH_ON_RELEASED)
    {
     wprint_button(v->test_window_element,v->test_button_element,PRESSED);
     while ((is_mouse_on_this_button(v->test_window_element,v->test_button_element)==T_TRUE)&&(vesa_mouse_button))
      vesa_mouse_update();
     if ((is_mouse_on_this_button(v->test_window_element,v->test_button_element)==T_TRUE)&&(!vesa_mouse_button))
      v->action=T_TRUE;
     wprint_button(v->test_window_element,v->test_button_element,RELEASED);
    }
    else
    {
     v->action=T_TRUE;
    }
    if (v->action==T_TRUE)
     if (v->test_button_element->button->button_funktion!=NULL)
      v->test_button_element->button->button_funktion(&(v->parameter));
   }
  } /*   if (vesa_mouse_button) */
/* dann auf eine Tastatur eingabe reagieren, wenn noch nichts anderes gemacht wurde */
  if ((v->key!=0)&&(v->parameter.executed==PARAMETER_NOT_EXECUTED))
  {
   if (dispatcher_type&ACTIVE_WINDOW)
   {
    // aktives Fenster aufrufen
    if (window_first!=NULL)
    {
     v->liste=window_first;
     while (v->liste)
     {
      v->test_window_element=((WINDOW_LISTEN_ELEMENT *)v->liste->objekt);
      if ((v->test_window_element->hide==0)&&((v->test_window_element->dhide==0)))
       break;
      v->test_window_element=NULL;
      v->liste=v->liste->naechstes;
     }
     v->parameter.window_element=v->test_window_element;
    }
   }
   if (v->test_window_element!=NULL)
   {
    if (v->test_window_element->tasten_funktion!=NULL)
     v->test_window_element->tasten_funktion(&(v->parameter));
    if (v->parameter.executed==PARAMETER_NOT_EXECUTED) // wenn noch nichts passiert ist
    {
     // Window button-default-tasten suchen
     T_LISTE *button_liste=v->test_window_element->button_first;
     while (button_liste)
     {
      if (((BUTTON_LISTEN_ELEMENT *)button_liste->objekt)->button->taste==v->key)
      {
       if (((BUTTON_LISTEN_ELEMENT *)button_liste->objekt)->button->button_funktion!=NULL)
       {
        v->parameter.button_element=(BUTTON_LISTEN_ELEMENT *)button_liste->objekt;
        ((BUTTON_LISTEN_ELEMENT *)button_liste->objekt)->button->button_funktion(&(v->parameter));
        break;
       }
      }
      button_liste=button_liste->naechstes;
     }
    }
   }
   if ((((dispatcher_type&ACTIVE_WINDOW) && (v->test_window_element==NULL))||(!(dispatcher_type&ACTIVE_WINDOW)))
   && (v->parameter.executed==PARAMETER_NOT_EXECUTED) )
   {
    if (back_tasten_funktion!=NULL)
     back_tasten_funktion(&(v->parameter));
    if (v->parameter.executed==PARAMETER_NOT_EXECUTED)
    {
     // Back button-default-tasten suchen
     T_LISTE *button_liste=button_first;
     while (button_liste)
     {
      if (((BUTTON_LISTEN_ELEMENT *)button_liste->objekt)->button->taste==v->key)
      {
       if (((BUTTON_LISTEN_ELEMENT *)button_liste->objekt)->button->button_funktion!=NULL)
       {
        ((BUTTON_LISTEN_ELEMENT *)button_liste->objekt)->button->button_funktion(&(v->parameter));
        break;
       }
      }
      button_liste=button_liste->naechstes;
     }
    }
   }
   if ((v->parameter.executed==PARAMETER_NOT_EXECUTED)&&(default_tasten_funktion!=NULL))
    default_tasten_funktion(&(v->parameter));
# ifndef NO_HIDDEN_INFOS
   if (v->parameter.executed==PARAMETER_NOT_EXECUTED)
    interne_tasten_funktion(&(v->parameter));
# endif
  } // key != 0
/* dann auf eine Tastatur einfach gucken, ob eine cursor positionsabhaengige aufgabe wartet */
  if ((v->test_window_element!=NULL)&&(v->test_window_element->area_funktion!=NULL)&&(v->parameter.executed==PARAMETER_NOT_EXECUTED))
   v->test_window_element->area_funktion(&(v->parameter));
  if ((back_area_funktion!=NULL)&&(v->parameter.executed==PARAMETER_NOT_EXECUTED))
   back_area_funktion(&(v->parameter));
  if ((default_area_funktion!=NULL)&&(v->parameter.executed==PARAMETER_NOT_EXECUTED))
   default_area_funktion(&(v->parameter));
# ifndef NO_HIDDEN_INFOS
  if (v->parameter.executed==PARAMETER_NOT_EXECUTED)
   interne_area_funktion(&(v->parameter));
# endif
  if (v->parameter.executed==PARAMETER_RETURNING)
  {
   break;
  }
  v->liste=update_funktion_first;
  while (v->liste!=NULL)
  {
   UPDATE_FUNCTION *update=(UPDATE_FUNCTION *)(v->liste->objekt);
   for(v->i=0;v->i<update->frequency;v->i++)
   {
    if (dispatcher_status==DISPATCHER_END) break;
    ((T_INT (*)(PARAMETER *))(update->update_funktion))(&(v->parameter));
   }
   v->liste=v->liste->naechstes;
  }
 }
 if (v!=NULL)
  free(v);
 if (dispatcher_type & HIDE_LOWER_WINDOWS)
  show_lower_return_windows(dispatcher_ebene);
 dispatcher_ebene--;
 T_DEBUG_LEAVE
 return;
}

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

T_VOID end_dispatcher(T_VOID)
{
 T_DEBUG_ENTRY("end_dispatcher",60)
 dispatcher_status=DISPATCHER_END;
 T_DEBUG_LEAVE
}

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

T_VOID dispatcher_missmatch(T_VOID)
{
 T_DEBUG_ENTRY("dispatcher_missmatch",60)
#ifdef SHOW_MISSMATCH
 show_message("\
  Zur Zeit koennen Rueckgabewerte aus Fenstern \n\
  nur in der Reihenfolge der Aufrufe abgearbeitet werden.\n\
  Bitte geben Sie vor der Beendigung DIESER Eingabe in das (die) andere(n) Fenster\n\
  ein, was immer dieses() jenige welches() erfordert(n).\n\
  \n\
  Wenn Jemand eine vernuenftige Loesung ohne Multitasking weiss,\n\
  dann bitte bei mir melden.\n\
  Auch CALLBACK Funktionen finde ich ohne Multitasking ziemlich aufwendig.\n\
  Vor allem auch sehr unbefriedigend, da die aufrufende Funktion doch ziemlich\n\
  beschnitten wird, oder?\n\
 ");
#endif
 T_DEBUG_LEAVE
}

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

T_VOID hide_lower_return_windows(T_INT this_dispatcher_ebene)
{
 T_LISTE *window_liste=window_first;
 T_LISTE *worked_on_first=NULL;
 T_LISTE *worked_on_last=NULL;
 WINDOW_LISTEN_ELEMENT *window;
 T_DEBUG_ENTRY("hide_lower_return_windows",60)
 while (window_liste!=NULL)
 {
  window=(WINDOW_LISTEN_ELEMENT *)window_liste->objekt;
  if (window->art&RETURNING)
  {
   VARIABLEN *v=window->variablen;
   if (v->ebene<this_dispatcher_ebene)
   {
    if (d_get_list_pos(&(window->id),worked_on_first)==NULL)
    {
     d_fuege_in_liste_ein(&(window->id),&worked_on_first,&worked_on_last,DL_HINTEN);
     if (window->dhide==0)
     {
      windows_shown--;
      repair_screen(window,HIDE_WINDOW,0,0,0,0);
      window_liste=window_first;
     }
     window->dhide++;
    }
   }
  }
  window_liste=window_liste->naechstes;
 }
 while (worked_on_first!=NULL)
  d_entferne_aus_liste(worked_on_first->objekt,&worked_on_first,&worked_on_last,DL_CLEAN_UP);
 T_DEBUG_LEAVE
}

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

T_VOID show_lower_return_windows(T_INT this_dispatcher_ebene)
{
 T_LISTE *window_liste=window_first;
 T_LISTE *worked_on_first=NULL;
 T_LISTE *worked_on_last=NULL;
 WINDOW_LISTEN_ELEMENT *window;
 T_DEBUG_ENTRY("show_lower_return_windows",60)
 while (window_liste!=NULL)
 {
  window=(WINDOW_LISTEN_ELEMENT *)window_liste->objekt;
  if (window->art&RETURNING)
  {
   VARIABLEN *v=window->variablen;
   if (v->ebene<this_dispatcher_ebene)
   {
    if (d_get_list_pos(&(window->id),worked_on_first)==NULL)
    {
     d_fuege_in_liste_ein(&(window->id),&worked_on_first,&worked_on_last,DL_HINTEN);
     window->dhide--;
     if (window->dhide==0)
     {
      windows_shown++;
      repair_screen(window,REDRAW_WINDOW,0,0,0,0);
      window_liste=window_first;
     }
    }
   }
  }
  window_liste=window_liste->naechstes;
 }
 while (worked_on_first!=NULL)
  d_entferne_aus_liste(worked_on_first->objekt,&worked_on_first,&worked_on_last,DL_CLEAN_UP);
 T_DEBUG_LEAVE
}

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

#endif
