/*****************************************************************************
*   Program to draw EE diagrams.					     *
*									     *
* This module creates new structs.					     *
*									     *
* Written by:  Gershon Elber			IBM PC Ver 1.0,	Oct. 1989    *
*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <dos.h>
#include <dir.h>
#include <alloc.h>
#include <time.h>
#include "Program.h"
#include "EEModify.h"
#include "EECreate.h"
#include "EERedraw.h"
#include "EELayer.h"
#include "Primary.h"	/* used for basic default layer numbers */

static DrawPolylineStruct
    *NewPolylineStruct = NULL;

static BooleanType CreateNewPolylineStructAux(DrawPolylineStruct *NewStruct,
	int TypeFlag);

/*****************************************************************************
* Routine called async. from the intr_lib tool kit when waiting for input    *
* events. Tests if cursor is out of the Active window and if so pan it and   *
* move the cursor to the center.					     *
*****************************************************************************/
void AutoPanActiveWindow(void)
{
    int DrawingWidth;
    IntrCursorShapeStruct Cursor;

    if (!EEAutoPan) return;

    if (EEActiveBBox -> Xmax < GRCurrentCursorX) {	   /* To the right. */
	DrawingWidth = GRInvMapX(EEActiveBBox -> Xmax) -
                       GRInvMapX(EEActiveBBox -> Xmin);/* In drawing space. */
        IntrWndwUpdatePanning(EEActiveWindow -> IntrLibWindowID,
        		      DrawingWidth / 2, 0);
	GRCurrentCursorX = (EEActiveBBox -> Xmax + EEActiveBBox -> Xmin) / 2;
    }
    else if (EEActiveBBox -> Xmin > GRCurrentCursorX) {     /* To the left. */
	DrawingWidth = GRInvMapX(EEActiveBBox -> Xmax) -
                       GRInvMapX(EEActiveBBox -> Xmin);/* In drawing space. */
        IntrWndwUpdatePanning(EEActiveWindow -> IntrLibWindowID,
        		      -DrawingWidth / 2, 0);
	GRCurrentCursorX = (EEActiveBBox -> Xmax + EEActiveBBox -> Xmin) / 2;
    }
    else if (EEActiveBBox -> Ymax < GRCurrentCursorY) {   /* To the bottom. */
	DrawingWidth = GRInvMapY(EEActiveBBox -> Ymax) -
                       GRInvMapY(EEActiveBBox -> Ymin);/* In drawing space. */
        IntrWndwUpdatePanning(EEActiveWindow -> IntrLibWindowID,
        		      0, DrawingWidth / 2);
	GRCurrentCursorY = (EEActiveBBox -> Ymax + EEActiveBBox -> Ymin) / 2;
    }
    else if (EEActiveBBox -> Ymin > GRCurrentCursorY) {      /* To the top. */
	DrawingWidth = GRInvMapY(EEActiveBBox -> Ymax) -
                       GRInvMapY(EEActiveBBox -> Ymin);/* In drawing space. */
        IntrWndwUpdatePanning(EEActiveWindow -> IntrLibWindowID,
        		      0, -DrawingWidth / 2);
	GRCurrentCursorY = (EEActiveBBox -> Ymax + EEActiveBBox -> Ymin) / 2;
    }
    else
	return;

    IntrWndwPop(EEActiveWindow -> IntrLibWindowID, TRUE, FALSE);

    if (NewPolylineStruct != NULL) {
	/* Find out where new position is in screen space. */
        Cursor = *IntrGetCursorType();
        Cursor.LastX = GRMapX(NewPolylineStruct -> Points[NewPolylineStruct ->
        						NumOfPoints * 2 - 2]);
        Cursor.LastY = GRMapY(NewPolylineStruct -> Points[NewPolylineStruct ->
        						NumOfPoints * 2 - 1]);
	IntrSetCursorType(&Cursor);
    }

    IntrInputFlush();   /* Any other events occuring outside active window. */
}

/*****************************************************************************
* Routine to create new polyline struct.				     *
*****************************************************************************/
DrawGenericStruct *CreateNewPolylineStruct(int Width,int TypeFlag)
{
    DrawPolylineStruct *NewStruct =
	(DrawPolylineStruct *) MyMalloc(sizeof(DrawPolylineStruct));

    NewStruct -> StructType = DRAW_POLYLINE_STRUCT_TYPE;
    NewStruct -> Width = Width;

    if (CreateNewPolylineStructAux(NewStruct,TypeFlag))
	return (DrawGenericStruct *) NewStruct;
    else {
	MyFree((VoidPtr) NewStruct);
	return NULL;
    }
}

/*****************************************************************************
* Aux routine to create new polyline struct.				     *
*****************************************************************************/
static BooleanType CreateNewPolylineStructAux(DrawPolylineStruct *NewStruct,
	int TypeFlag)
{
    int x, y, *TempPoints,
        AllocatedNumOfPoints = 5,
        Quit = FALSE;
    IntrCursorShapeStruct Cursor;
    IntrEventType Event;

    NewStruct -> Pnext = NULL;
    NewStruct -> NumOfPoints = 0;
    NewStruct -> Points = (int *)
	MyMalloc(sizeof(int) * AllocatedNumOfPoints * 2);

    /* Put the structure in the global struct list, so automatic panning     */
    /* will draw it as well. It will be removed from EEDrawList before exit. */
    NewStruct -> Pnext = EEActiveWindow -> EEDrawList;
    EEActiveWindow -> EEDrawList = (DrawGenericStruct *) NewStruct;

    IntrPushCursorType();
    Cursor.CursorType = INTR_CURSOR_CROSS;
    Cursor.LastHV = EEHVLineDrawing;
    Cursor.LastX = Cursor.LastY = 0;
    IntrSetCursorType(&Cursor);

    IntrDrawMessage("Pick Polyline point:", EEPopUpForeColor, EEPopUpBackColor);

    PutCursorInActiveWindow();
    IntrSetIdleFunction(AutoPanActiveWindow);

    NewPolylineStruct = NewStruct;            /* Make it globally available. */

    while (!Quit) {
	Event = IntrGetEventWaitSA(&x, &y);
	Cursor.LastX = x;
	Cursor.LastY = y;
	x = EE_SNAP(GRInvMapX(x));
	y = EE_SNAP(GRInvMapY(y));

	if (NewStruct -> NumOfPoints > 0) {
	    if(TypeFlag==FALSE)
	    	NewStruct -> Layer = ReturnCurrentLayer();
	    else
		NewStruct -> Layer = LAYER_WIRE;
	    if (EEHVLineDrawing) {
	        /* Coerce the line to vertical or horizontal one: */
	        if (ABS(x - NewStruct -> Points[NewStruct -> NumOfPoints * 2 - 2]) <
		    ABS(y - NewStruct -> Points[NewStruct -> NumOfPoints * 2 - 1]))
		    x = NewStruct -> Points[NewStruct -> NumOfPoints * 2 - 2];
	        else
		    y = NewStruct -> Points[NewStruct -> NumOfPoints * 2 - 1];
	    }
        }

	switch (Event) {
	    case INTR_EVNT_ABORT:
		if (NewStruct -> NumOfPoints > 0) {
		    RedrawPolylineStruct(NewStruct, GR_COPY_PUT, EE_ERASE_COLOR);
		    if (--NewStruct -> NumOfPoints > 0) {
			RedrawPolylineStruct(NewStruct, GR_COPY_PUT, EE_DRAW_COLOR);
			Cursor.LastX = GRMapX(NewStruct ->
                        	    Points[NewStruct -> NumOfPoints * 2 - 2]);
			Cursor.LastY = GRMapY(NewStruct ->
                        	    Points[NewStruct -> NumOfPoints * 2 - 1]);
		    }
		}
		else
		    Quit = TRUE;
		break;
	    case INTR_EVNT_SELECT:
		if (NewStruct -> NumOfPoints > 0 &&
		    NewStruct -> Points[NewStruct -> NumOfPoints * 2 - 2] == x &&
		    NewStruct -> Points[NewStruct -> NumOfPoints * 2 - 1] == y) {
		    /* If same point as last one - quit, we are done. */
		    Quit = TRUE;
		    break;
		}

		if (NewStruct -> NumOfPoints >= AllocatedNumOfPoints) {
		    /* Reallocate into the double the space: */
		    TempPoints = (int *)
			MyMalloc(sizeof(int) * AllocatedNumOfPoints * 4);
		    GEN_COPY(TempPoints, NewStruct -> Points,
				sizeof(int) * AllocatedNumOfPoints * 2);
		    MyFree((VoidPtr) NewStruct -> Points);
		    AllocatedNumOfPoints *= 2;
		    NewStruct -> Points = TempPoints;
		}
		NewStruct -> Points[NewStruct -> NumOfPoints * 2] = x;
		NewStruct -> Points[NewStruct -> NumOfPoints++ * 2 + 1] = y;
		Cursor.LastX = GRMapX(x);
		Cursor.LastY = GRMapY(y);

		break;
	    case INTR_EVNT_MIDDLE_BUTTON:
		Quit = TRUE;
		break;
	}

	if (NewStruct -> NumOfPoints > 0) {		     /* Lets see it. */
	    Cursor.CursorType = INTR_CURSOR_CROSS_LAST;
	    IntrSetCursorType(&Cursor);
	    RedrawPolylineStruct(NewStruct, GR_COPY_PUT, 
		ReturnLayerColor(NewStruct -> Layer));
/* 	    RedrawPolylineStruct(NewStruct, GR_COPY_PUT, EE_DRAW_COLOR); */
	}
	else {
	    Cursor.CursorType = INTR_CURSOR_CROSS;
	    IntrSetCursorType(&Cursor);
        }
    }

    NewPolylineStruct = NULL;

    IntrSetIdleFunction(NULL);

    IntrEraseMessage();
    IntrPopCursorType();

    /* Remove from global list. */
    EEActiveWindow -> EEDrawList = EEActiveWindow -> EEDrawList -> Pnext;
    NewStruct -> Pnext = NULL;

    if (NewStruct -> NumOfPoints < 2) {	 /* Dont consider it a new polyline. */
	MyFree((VoidPtr) NewStruct -> Points);
	NewStruct -> Points = NULL;
	return FALSE;
    }
    else
	return TRUE;
}

/*****************************************************************************
* Routine to create new connection struct.				     *
*****************************************************************************/
DrawGenericStruct *CreateNewConnectionStruct(void)
{
    IntrCursorShapeStruct Cursor;
    DrawConnectionStruct *NewStruct =
	(DrawConnectionStruct *) MyMalloc(sizeof(DrawConnectionStruct));

    NewStruct -> StructType = DRAW_CONNECTION_STRUCT_TYPE;
    NewStruct -> Pnext = NULL;

    IntrDrawMessage("Pick Connection point:", EEPopUpForeColor, EEPopUpBackColor);

    IntrPushCursorType();
    Cursor.CursorType = INTR_CURSOR_CROSS;
    IntrSetCursorType(&Cursor);

    PutCursorInActiveWindow();
    IntrSetIdleFunction(AutoPanActiveWindow);

    if (IntrGetEventWaitSA(&NewStruct -> PosX, &NewStruct -> PosY) ==
							INTR_EVNT_SELECT) {
	NewStruct -> Layer = LAYER_WIRE;	/* Use Wire Layer */
	IntrSetIdleFunction(NULL);
	NewStruct -> PosX = EE_SNAP(GRInvMapX(NewStruct -> PosX));
	NewStruct -> PosY = EE_SNAP(GRInvMapY(NewStruct -> PosY));
	RedrawConnectionStruct(NewStruct, GR_COPY_PUT,
		ReturnLayerColor(NewStruct -> Layer));
	/* RedrawConnectionStruct(NewStruct, GR_COPY_PUT, EE_DRAW_COLOR); */
	IntrEraseMessage();
	IntrPopCursorType();
	return (DrawGenericStruct *) NewStruct;
    }
    else {
	IntrSetIdleFunction(NULL);
	MyFree((VoidPtr) NewStruct);
	IntrEraseMessage();
	IntrPopCursorType();
	return NULL;
    }
}

/*****************************************************************************
* Routine to create new text struct.					     *
*****************************************************************************/
DrawGenericStruct *CreateNewTextStruct(void)
{
    char Text[LINE_LEN];
    DrawTextStruct *NewStruct =
	(DrawTextStruct *) MyMalloc(sizeof(DrawTextStruct));

    NewStruct -> StructType = DRAW_TEXT_STRUCT_TYPE;
    NewStruct -> Scale = EETextScale;
    NewStruct -> Pnext = NULL;

    Text[0] = 0;
    IntrQueryLine("Text:", Text, LINE_LEN - 1, EEPopUpFrameColor,
                  EEPopUpBackColor, EEPopUpForeColor, EEWindowsFrameWidth,
                  INTR_WNDW_PLACE_CENTER);

    NewStruct -> PosX = NewStruct -> PosY = -1;
    if (strlen(Text) == 0 ||
	!PlaceString(Text, &NewStruct -> Orient, NewStruct -> Scale,
		     &NewStruct -> PosX, &NewStruct -> PosY,
                     INTR_WNDW_PLACE_CENTER)) {
	MyFree((VoidPtr) NewStruct);
	return NULL;
    }
    else {
	NewStruct -> Layer = ReturnCurrentLayer();
	NewStruct -> Text = strdup(Text);
	RedrawTextStruct(NewStruct, GR_COPY_PUT, 
		ReturnLayerColor(NewStruct -> Layer));
	/* RedrawTextStruct(NewStruct, GR_COPY_PUT, EE_DRAW_COLOR); */
	return (DrawGenericStruct *) NewStruct;
    }
}
