/* soaring specific functions */

#include <stdio.h>
#include <string.h>

#include <Xm/Xm.h>
#include <Xm/List.h>
#include <Xm/PushB.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/RowColumn.h>
#include <Xm/TextF.h>
#include <Xm/DialogS.h>
#include <Xm/ToggleB.h>



#include "objects.h"
#include "popup.h"
#include "busy.h"


#define FROM  0
#define VIA1  1
#define VIA2  2
#define VIA3  3
#define DEST  4

extern OBJECT *currentroute[];
extern Display *display;

extern Widget toplevel;

extern OBJECT **objectlist;       /* objects.c */
extern int db_objects;            /* number of objects */
extern Cursor pointer, waitpointer;

#define MAXROUTES 5000
char **routearray;
char str_km[20];
Widget km, trianglelist, shell, browser, kmfield;

OBJECT *turn1[MAXROUTES];     /* store suggested routes here */
OBJECT *turn2[MAXROUTES];

OBJECT *selected1, *selected2;  /* waypoints of selected route */

int numberofroutes;

int firstsuggest = 1;      /* still need to manage browser widget on suggest button? */


/* trim name to 20 chars */

char *trim (char *string)
{
  static char temp[256];
  int i;
  
  strcpy (temp, string);
  temp[30] = 0;

  while (strlen(temp) < 30)
    strcat (temp, " ");

  for (i=0; i<strlen(temp); i++)
    if (temp[i] == '_')
      temp[i] = ' ';

  return temp;
}



/* check if triangle conforms to FAI rules */

int isFAITriangle (LOCATION a, LOCATION b, LOCATION c)
{
  double totaldist, dist1, dist2, dist3, minside, maxside;
  int ok;

  ok = 1;
  dist1 = distance (a, b);
  dist2 = distance (b, c);
  dist3 = distance (c, a);

  totaldist = dist1 + dist2 + dist3;

  if (totaldist >= 500/1.852)
    minside = totaldist * 0.25;
  else
    minside = totaldist * 0.28;
  maxside = totaldist * 0.45;

  if ((dist1 < minside) || (dist2 < minside) || (dist3 < minside))
    ok = 0;

  if ((dist1 > maxside) || (dist2 > maxside) || (dist3 > maxside))
    ok = 0;

  return ok;
}



/* get object name and description string */

char *makedesc (OBJECT *object)
{
  static char temp[256];
  int i;

  if (object->type != O_WAYPOINT)
    sprintf (temp, "%s (%s)", object->name,
	     objecttypestring (object->type));
  else
    if (object->alias)
      sprintf (temp, "%s %s", object->name, object->alias);
    else
      sprintf (temp, "%s", object->name);

  for (i=0; i<strlen(temp); i++)
    if (temp[i] == '_')
      temp[i] = ' ';

  return temp;
}



void update_route_button (int button, OBJECT *object);


/* callback for list selection */


void trianglebrowserCB (Widget w, XtPointer client_data, XmListCallbackStruct *cbs)
{
  int doubleclick = (int) client_data;

  if (doubleclick)
    {
      currentroute[VIA1] = turn1[cbs->item_position-1];
      currentroute[VIA2] = turn2[cbs->item_position-1];
      currentroute[VIA3] = NULL;
      currentroute[DEST] = currentroute[FROM];

      update_route_button (VIA1, turn1[cbs->item_position-1]);
      update_route_button (VIA2, turn2[cbs->item_position-1]);
      update_route_button (VIA3, NULL);
      update_route_button (DEST, currentroute[FROM]);

      drawcurrentroute();
    }
/*  else
    puts ("Route gewaehlt"); */
}




/* display info for selected route */

void infoCB (Widget w, XtPointer client_data, XmPushButtonCallbackStruct *cbs)
{
  int i;
  double d1, d2, d3;

  if (selected1 && selected2)
    {
      i = 0;

      sprintf (popupstrings[i++], "Selected Route:");
      sprintf (popupstrings[i++], "  %s", makedesc (currentroute[FROM]));
      sprintf (popupstrings[i++], "  %s", makedesc (selected1));
      sprintf (popupstrings[i++], "  %s", makedesc (selected2));
      sprintf (popupstrings[i++], "");
      sprintf (popupstrings[i++], "                                       Hdg      km");
      sprintf (popupstrings[i++], "--------------------------------------------------");
      sprintf (popupstrings[i++], "From: %s %5.1f %7.1f", trim(currentroute[FROM]->name), truetrack(currentroute[FROM]->location, selected1->location), d1 = 1.852*distance(currentroute[FROM]->location, selected1->location));
      sprintf (popupstrings[i++], "Via:  %s %5.1f %7.1f", trim(selected1->name), truetrack(selected1->location, selected2->location), d2 = 1.852*distance(selected1->location, selected2->location));
      sprintf (popupstrings[i++], "Via:  %s %5.1f %7.1f", trim(selected2->name), truetrack(selected2->location, currentroute[FROM]->location), d3 = 1.852*distance(selected2->location, currentroute[FROM]->location));
      sprintf (popupstrings[i++], "To:   %s        ======", trim(currentroute[FROM]->name));
      sprintf (popupstrings[i++], "%50.1f", d1+d2+d3); 

      popupbox (i, "Route Suggestion");
    }
}


/* close dialog */

void cancelCB (Widget w, XtPointer client_data, XmPushButtonCallbackStruct *cbs)
{
  Widget parent;

  parent = XtParent (w);
  parent = XtParent (parent);

  XtPopdown (parent);
}


/* select triangle */

void trianglelistCB (Widget w, XtPointer client_data, XmListCallbackStruct *cbs)
{
#ifdef 0
  XawListReturnStruct *selection;

  selection = (XawListReturnStruct *) client_data;

  selected1 = turn1[selection->list_index];
  selected2 = turn2[selection->list_index];
#endif
}


/* suggest triangle */

void suggestCB (Widget w, XtPointer client_data, XmPushButtonCallbackStruct *cbs)
{
  int i, j, numberofturns, index;
  Arg recArglist[10];
  OBJECT *turns[1000];    /* possible waypoints */
  double mindist, maxdist, minside, maxside;
  double totaldistance, tempdist;
  char *tempstring;
  char temp[250];
  XmString *strings;

  /* read distance from input field */
  
  XtVaGetValues (kmfield,
		 XmNvalue, &tempstring,
		 NULL);

  sscanf (tempstring, "%lf", &totaldistance);
  totaldistance = totaldistance / 1.852;   /* NM */


  if (currentroute[FROM] && totaldistance) /* don't try if no start point specified */
    {
      
      /* this may take a while... */

      TimeoutCursors (True, True);

      numberofturns = 0;
      
      /* FAI triangle: each side must be at least 28% of the total distance,
	 no side may be longer then 45% of the total distance: */
      
      mindist = totaldistance;
      maxdist = totaldistance + 8;   /* 8 NM tolerance */
      
      minside = mindist * 0.28;
      maxside = maxdist * 0.45;
      if (maxdist > 500/1.852)       /* 500+ km: shortest side only needs to be 25 % */
	minside = mindist * 0.25;
      
      for (i=0; i<db_objects; i++)
	{
	  tempdist = distance (currentroute[FROM]->location, objectlist[i]->location);
	  if ((tempdist >= minside) && (tempdist <= maxside))
	    if (((objectlist[i]->type < O_VOR) ||
		 (objectlist[i]->type == O_WAYPOINT) ||
		 (objectlist[i]->type == O_LAKE)) &&
		(objectlist[i]->name) && ((*objectlist[i]).name[0]))
	      {
		turns[numberofturns] = objectlist[i];
		if (numberofturns < 1000)
		  numberofturns++;
	      }
	}
      
      /* check possible triangles */

      numberofroutes = 0;

      for (i=0; i<numberofturns-1; i++)
	{
	  if (CheckForInterrupt())
	    break;

	  for (j=i+1; j<numberofturns; j++)
	    {
	      tempdist = distance (currentroute[FROM]->location, turns[i]->location) +
		distance (turns[i]->location, turns[j]->location) +
		  distance (turns[j]->location, currentroute[FROM]->location);
	      
	      if ((tempdist >= mindist) && (tempdist <= maxdist))
		if (isFAITriangle (currentroute[FROM]->location, turns[i]->location,
				   turns[j]->location))
		  {
		    turn1[numberofroutes] = turns[i];
		    turn2[numberofroutes] = turns[j];
		    if (numberofroutes < MAXROUTES)
		      numberofroutes++;
		  }
	    }
	}

      /* evaluate ease of route, sort accordingly */
      
      /* (still to be done...) */

      /* add found routes to string list */

      strings = (XmString *) malloc (sizeof (XmString) * numberofroutes);
      index = 0;

      for (i=0; i<numberofroutes; i++)
	{
	  tempdist = distance (currentroute[FROM]->location, turn1[i]->location) +
	    distance (turn1[i]->location, turn2[i]->location) +
	      distance (turn2[i]->location, currentroute[FROM]->location);

	  sprintf (temp, "%4.0lf km: %s - %s - %s", 1.852 * tempdist, 
		   currentroute[FROM]->name, turn1[i]->name,
		   turn2[i]->name);

	  for (j=0; j<strlen(temp); j++)
	    if (temp[j] == '_')
	      temp[j] = ' ';

	  strings[index++] = XmStringCreateSimple (temp);
	}

      /* delete old strings from list */

      XmListDeleteAllItems (browser);

      /* update list widget */

      XmListAddItems (browser, strings, numberofroutes, 0);

      /* free strings */

      for (i=0; i<numberofroutes; i++)
	XmStringFree (strings[i]);

      free (strings);


      /* if this was the first suggestion, manage browser to display */
      
      if (firstsuggest)
	{
	  XtVaSetValues (browser,
			 XmNheight, 150,
			 NULL);
	  
	  XtManageChild (browser);
	  firstsuggest = 0;
	}      

      TimeoutCursors (False, NULL);

    }     
}



/* close form */

void closeCB (Widget w, XtPointer client_data, XmPushButtonCallbackStruct *cbs)
{
  Widget shell = (Widget) client_data;

  XtUnmanageChild (shell);
  XtDestroyWidget (shell);
}




/* suggest triangles, user interface */

void triangle ()
{
  int index, i;
  Arg args[20];
  Widget start, stats, stats1, stats2, label, label1, bclose,
         b1000, bcancel, bsuggest, form, nameviewport, binfo, rowcol;
  String to, km, suggest, quit, tempstr;


  firstsuggest = 1;

  /* init string array */

  routearray = (char **) malloc (MAXROUTES * sizeof (char *));
  for (i=0; i<MAXROUTES; i++)
    routearray[i] = NULL;
  
  /* default: 300 km */

  strcpy (str_km, "300");

  selected1 = selected2 = NULL;

  /* popup shell[5~ */

  shell = XtVaCreateWidget ("triangledialog", xmDialogShellWidgetClass, toplevel,
			    XmNtitle,            "ICAO Suggest FAI Triangle",
			    XmNdeleteResponse,   XmDESTROY,
			    XmNallowShellResize, True,
			    NULL);
  
  form = XtVaCreateWidget ("triangleform", xmFormWidgetClass, shell, 
				  XmNautoUnmanage,     False,
				  NULL);



  tempstr = XmStringCreateSimple ("  Choose a distance and click <Suggest>:  ");
  label1 = XtVaCreateManagedWidget ("trianglelabel", xmLabelWidgetClass, form,
				    XmNlabelString,      tempstr,
				    XmNtopAttachment,    XmATTACH_FORM,
				    XmNleftAttachment,   XmATTACH_FORM,
				    XmNrightAttachment,  XmATTACH_FORM,
				    XmNalignment,        XmALIGNMENT_CENTER, 
				    NULL);
  XmStringFree (tempstr);  


  rowcol = XtVaCreateManagedWidget ("trianglemanager", xmRowColumnWidgetClass, form,
				    XmNpacking,          XmPACK_COLUMN,
				    XmNorientation,      XmVERTICAL,
				    XmNnumColumns,       2,
				    XmNtopAttachment,    XmATTACH_WIDGET,
				    XmNtopWidget,        label1,
				    XmNleftAttachment,   XmATTACH_FORM,
				    XmNleftOffset,       10,
				    NULL);

  tempstr = XmStringCreateSimple ("Start at:");
  label = XtVaCreateManagedWidget ("trianglelabel", xmLabelWidgetClass, rowcol,
				   XmNlabelString,      tempstr,
				   XmNalignment,        XmALIGNMENT_BEGINNING, 
				   NULL);
  XmStringFree (tempstr);  



  /* distance label */

  tempstr = XmStringCreateSimple ("Distance: (km)");
  label = XtVaCreateManagedWidget ("trianglelabel", xmLabelWidgetClass, rowcol,
				   XmNlabelString,      tempstr,
				   XmNalignment,        XmALIGNMENT_BEGINNING, 
				   NULL);
  XmStringFree (tempstr);  


  /* take off location */

  if (currentroute[FROM])
    tempstr = XmStringCreateSimple (currentroute[FROM]->name);
  else
    tempstr = XmStringCreateSimple ("UNDEFINED!");

  label = XtVaCreateManagedWidget ("trianglelabel", xmLabelWidgetClass, rowcol,
				   XmNlabelString,      tempstr,
				   XmNalignment,        XmALIGNMENT_BEGINNING, 
				   NULL);
  XmStringFree (tempstr);  



  /* km text field */

  kmfield = XtVaCreateManagedWidget ("trianglerange", xmTextFieldWidgetClass, rowcol,
				     XmNvalue,       str_km,
				     XmNmaxLength,   5,
				     NULL);


  /* we need one dummy label that can extend in size between the rowcol
     and the suggest button: */

  tempstr = XmStringCreateSimple (" ");
  label = XtVaCreateManagedWidget ("dummylabel", xmLabelWidgetClass, form,
				   XmNlabelString,      tempstr,
				   XmNtopAttachment,    XmATTACH_WIDGET,
				   XmNtopWidget,        label1,
				   XmNtopOffset,        10,
				   XmNrightAttachment,  XmATTACH_FORM,
				   XmNrightOffset,      100,
				   XmNleftAttachment,   XmATTACH_WIDGET,
				   XmNleftWidget,       rowcol,
				   NULL);
  XmStringFree (tempstr);  


  
  /* Suggest Button */

  tempstr = XmStringCreateSimple ("Suggest");
  bsuggest = XtVaCreateManagedWidget ("trianglesuggest", xmPushButtonWidgetClass, form,
				      XmNtopAttachment,    XmATTACH_WIDGET,
				      XmNtopWidget,        label1,
				      XmNtopOffset,        10,
				      XmNrightAttachment,   XmATTACH_FORM,
				      XmNrightOffset,       10,
				      XmNleftAttachment,   XmATTACH_WIDGET,
				      XmNleftWidget,       label,
				      XmNleftOffset,       10,
				      XmNlabelString,      tempstr,
				      NULL);
  XmStringFree (tempstr);

  XtAddCallback (bsuggest, XmNactivateCallback, (XtCallbackProc) suggestCB, NULL);




  /* triangle browser */

  
  i=0;
  XtSetArg (args[i], XmNtopAttachment,    XmATTACH_WIDGET);  i++;
  XtSetArg (args[i], XmNtopWidget,        rowcol);           i++;
  XtSetArg (args[i], XmNtopOffset,        5);                i++;
  XtSetArg (args[i], XmNleftOffset,       5);                i++;
  XtSetArg (args[i], XmNrightOffset,      5);                i++;
  XtSetArg (args[i], XmNbottomAttachment, XmATTACH_FORM);    i++;
  XtSetArg (args[i], XmNbottomOffset,     38);               i++;    
  XtSetArg (args[i], XmNleftAttachment,   XmATTACH_FORM);    i++;
  XtSetArg (args[i], XmNrightAttachment,  XmATTACH_FORM);    i++;
  
  browser = XmCreateScrolledList (form, "triangles", args, i);
  
  XtAddCallback (browser, XmNdefaultActionCallback, 
		 (XtCallbackProc) trianglebrowserCB, (XtPointer) 1);
  XtAddCallback (browser, XmNbrowseSelectionCallback, 
		 (XtCallbackProc) trianglebrowserCB, (XtPointer) 0);
  
  XtVaSetValues (browser,
		 XmNheight, 1,
		 NULL);

  XtManageChild (browser);


  /* Close Button */

  tempstr = XmStringCreateSimple ("Close");
  bclose = XtVaCreateManagedWidget ("triangleclose", xmPushButtonWidgetClass, form,
				    XmNtopAttachment,    XmATTACH_WIDGET,
				    XmNtopWidget,        browser,
				    XmNtopOffset,        5,
				    XmNleftAttachment,   XmATTACH_FORM,
				    XmNleftOffset,       10,
				    XmNlabelString,      tempstr,
				    NULL);
  XmStringFree (tempstr);

  XtAddCallback (bclose, XmNactivateCallback, (XtCallbackProc) closeCB, shell);




  /* display complete dialog */

  XtManageChild (form);  
  XtManageChild (shell);


}



#if 0


  


  /* Quit Button */

  i = 0;
  XtSetArg (recArglist[i], XtNright, XtChainLeft); i++;
  XtSetArg (recArglist[i], XtNleft, XtChainLeft); i++;
  XtSetArg (recArglist[i], XtNbottom, XtChainBottom); i++;
  XtSetArg (recArglist[i], XtNtop, XtChainBottom); i++;
  XtSetArg (recArglist[i], XtNlabel, "Close"); i++;
  XtSetArg (recArglist[i], XtNvertDistance, 10); i++;
  XtSetArg (recArglist[i], XtNfromVert, nameviewport); i++;
  bcancel = XtCreateManagedWidget ("tCancel", commandWidgetClass, form, recArglist, i);
  XtAddCallback (bcancel, XtNcallback, cancelCB, NULL);

  /* route info button */

  i = 0;
  XtSetArg (recArglist[i], XtNright, XtChainLeft); i++;
  XtSetArg (recArglist[i], XtNleft, XtChainLeft); i++;
  XtSetArg (recArglist[i], XtNbottom, XtChainBottom); i++;
  XtSetArg (recArglist[i], XtNtop, XtChainBottom); i++;
  XtSetArg (recArglist[i], XtNlabel, "Info"); i++;
  XtSetArg (recArglist[i], XtNvertDistance, 10); i++;
  XtSetArg (recArglist[i], XtNfromVert, nameviewport); i++;
  XtSetArg (recArglist[i], XtNhorizDistance, 10); i++;
  XtSetArg (recArglist[i], XtNfromHoriz, bcancel); i++;
  binfo = XtCreateManagedWidget ("tInfo", commandWidgetClass, form, recArglist, i);
  XtAddCallback (binfo, XtNcallback, infoCB, NULL);




  
  XtPopup (popupShell, XtGrabNone);
}
#endif


