/*
 * Copyright 1988 Anant Agarwal
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation.  No representations about the suitability of this software
 * for any purpose.  It is provided "as is" without express or implied 
 * warranty.
 *
 * Author:  Anant Agarwal, MIT Laboratory for Computer Science
 */

#include <strings.h>	
#include <stdio.h>
#include <math.h>
#include "plotio.h"
#include "defs.h"
#include "structs.h"
#include "plot.h"

#define DEGTORAD 0.0174



#define	TestForSpecialStart						\
   if ((p->un.text.StrPtr[i+2] != '{')||				\
       (p->un.text.StrPtr[i+3] == '\0'))				\
   {									\
	fprintf(stderr,"splot error: Check your special text\n");	\
	exit(1);							\
   }

static SpecialType Special;
static boolean StartSpecial = FALSE;

extern double getdegrees(), atan(), charheight(),charwidth(),log10(),mylog();
extern double cos(), sin();

static double NewLineSpacingMul = 1.05;/*multiply this to charheight */

static char NullStr[] = "";


printtext()
{
int c;/* current text */
	c = 0;
	while ((text[c] != nil)&&((text[c])->validtext))
	{
		if ((text[c])->include)
		{
			(obj[curobj])->name = objtext;
			(obj[curobj])->un.text.fontsize = FFsize((text[c])->font);
			(obj[curobj])->scale = TRUE;
			(obj[curobj])->from[xpt] = (text[c])->pos[xpt];
			(obj[curobj])->from[ypt] = (text[c])->pos[ypt];
			(obj[curobj])->un.text.angle = (text[c])->angle;
				/*def hor*/
			(obj[curobj])->un.text.Sp = norml;
			(obj[curobj])->un.text.FF = FF((text[c])->font);
			(obj[curobj])->un.text.StrPtr = (text[c])->label;
			(obj[curobj])->un.text.align = (text[c])->align;
			(obj[curobj])->un.text.font = (text[c])->font;
			GetNewObjcurobj();
		}
		c++;
	}
}

static int k=0;/* counts how many lines down. Actually always one or zero */


/* called from plotsend */
HandleSpecialText(p)
  LocalObjectType *p;
{
/*
   Puts first substring that follows \n in given string in a new object.
   If the substring has more returns, it will appear again anyway.
   If it gets a special it does its thing and continues.
*/ 
int i=0;
int g=0;
boolean GotReturn = FALSE;

	k = 0;
	StartSpecial = FALSE;
	while ((p->un.text.StrPtr[i] != '\0')&&(!GotReturn))
	{
	   switch (p->un.text.StrPtr[i])
	   {
		case '\n':
			k++;
			GotReturn = TRUE;
			PIntoObj(p);
			(obj[curobj])->un.text.StrPtr = 
				&(p->un.text.StrPtr[i+1]);
			(obj[curobj])->from[ypt] -=
			 	k * NewLineSpacingMul * 
					CMPT * charheight(p->un.text.font);
			GetNewObjcurobj();
			p->un.text.StrPtr[i] = '\0';
		break;
		case '\\':
		   switch (p->un.text.StrPtr[i+1])
		   {
			case 'n':
			   k++;
			   GotReturn = TRUE;
			   PIntoObj(p);
		   	   (obj[curobj])->un.text.StrPtr = 
			   	&(p->un.text.StrPtr[i+2]);
		   	   (obj[curobj])->from[ypt] -=
			    	k * NewLineSpacingMul * 
			   	     CMPT * charheight(p->un.text.font);
			   GetNewObjcurobj();
			   p->un.text.StrPtr[i] = '\0';
			   i++;
			break;
			case 'g':/* greek text */
			case '+':/* superscript */
			case '^':/* superscript */
			case '-':/* subscript  */
			case '_':/* subscript  */
		   	switch (p->un.text.StrPtr[i+1])
			{
				case 'g': Special = grk;break;
				case '^':
				case '+': Special = pls;break;
				case '_':
				case '-': Special = mns;break;
				default:	break;
			}

			   /* idea: put orig text into new obj and neuter
				p because need to be contiguous.
				Put greek text within braces into next obj and
				Set FF to Greek.
				Insert plain text upto either \n or \ into
				another object.
			       	no k++ here as not newline 
			   */
			   PutStartTextIntoNewObj(p,i);
			   StartSpecial = TRUE;

			   /* no GotReturn here. Grab greek stuff and put into
				an object. Then continue loop */
			   PIntoObj(p);
			   (obj[curobj])->name = objCurText;/*rel text*/
			   /* actually make it greek and make greek symbol */
			   TestForSpecialStart;
		   	   (obj[curobj])->un.text.StrPtr = 
			   	&(p->un.text.StrPtr[i+3]);
				/* i + 2 points to a brace of sorts */
				/* now zap end of brace to end of line */
			   g = i+3;
			   g += TestForSpecialEndAndZapAndY(p);
				/*g is set to end, i.e. g has \0 */
			
			   SpecialSpecial();
			     	/* enters special type related stuff */

			   GetNewObjcurobj();
			   g++;/* after brace, i.e. after \0 */
				
			   /* put remaining into a new obj and send */
			   /* make SpStrPtr non nil and equal to () */
			   /* so that plotpsf sends non-absolute text */
			   g = PutRemIntoObj(p,g);/* return new start pt */
			   i = g-1;/*g comes back pointing to say, \.
					Note i++ later */
			break;
			case '\\':
				p->un.text.StrPtr[i] = '\n';/*neuter
					one backslash */
				i++;i++;
			break;/*two backslashes is a backslash */
			default:
/*				fprintf(stderr,"splot error: strange special character \n");*//*OK becos could be escape char */
				i++;
			break;
		   }
		break;
		default:
		break;
	   }
	   i++;
	}
}



PutStartTextIntoNewObj(p,i)
  LocalObjectType *p;
  int i;/* cur index into text*/
{
/* puts first text string into new obj and neuters old string */
 if (!StartSpecial)
 {
   PIntoObj(p); 
   (obj[curobj])->un.text.StrPtr = p->un.text.StrPtr;
   FudgeStrWidth(obj[curobj]);
	/* adjusts for str width if not left justified */
   p->un.text.StrPtr[i] = '\0';
   p->name = objdummy;/*neuter p*/
   (obj[curobj])->from[ypt] -=
 	k * NewLineSpacingMul * 
		CMPT * charheight(p->un.text.font);
   GetNewObjcurobj();
 }
 else 
  p->un.text.StrPtr[i] = '\0';/* just eoln prev obj */
}

PutRemIntoObj(p,g)
  LocalObjectType *p;
  int g;/* cur index into text*/
{
/* puts first text string into new obj and neuters old string */
   PIntoObj(p); 
   (obj[curobj])->un.text.StrPtr = &(p->un.text.StrPtr[g]);
   (obj[curobj])->name = objCurText;/*rel text*/
   FudgeStrWidth(obj[curobj]);
   while (
	   (p->un.text.StrPtr[g] != '\n')&&
	   (p->un.text.StrPtr[g] != '\\')&&
	   (p->un.text.StrPtr[g] != '\0')
	 )
  {
	g++;
	/*no need to zap end of text because it will be done in next iter */
  }
	/* no need to neuter one of two backslashes, gets done next iter */
   (obj[curobj])->un.text.Sp = norml;/* possibly normal */
   (obj[curobj])->from[ypt] -=
 	k * NewLineSpacingMul * 
		CMPT * charheight(p->un.text.font);
   GetNewObjcurobj();
   return(g);
}

PIntoObj(p)
  LocalObjectType *p;
{
	   (obj[curobj])->name = objtext;/* becos p->name may become dummy */
	   (obj[curobj])->un.text.fontsize = p->un.text.fontsize;
	   (obj[curobj])->un.text.font = p->un.text.font;
	   (obj[curobj])->un.text.up = 0.0;/*default inline with text */
	   (obj[curobj])->un.text.Sp = norml;/*default normal text */
	   (obj[curobj])->scale = p->scale;
	   (obj[curobj])->from[xpt] = p->from[xpt];
	   (obj[curobj])->from[ypt] = p->from[ypt];

	   (obj[curobj])->un.text.angle = p->un.text.angle;
	   (obj[curobj])->un.text.FF = p->un.text.FF;
	   (obj[curobj])->un.text.align = p->un.text.align;

	   if ((obj[curobj])->scale)
	   	scaleobj(obj[curobj]);
	   (obj[curobj])->scale = FALSE;
}

TestForSpecialEndAndZapAndY(p)
  LocalObjectType *p;
{									
int g = 0;
   while ((obj[curobj])->un.text.StrPtr[g] != '}')			
   {									
     if ((obj[curobj])->un.text.StrPtr[g] == '\0')			
     {									
	fprintf(stderr,"splot error: No closing brace in greek text\n");
	exit(1);							
     }
     else if (((obj[curobj])->un.text.StrPtr[g] == '\\')&&
		((obj[curobj])->un.text.StrPtr[g+1] == '\\'))
	(obj[curobj])->un.text.StrPtr[g] = '\n';/* neuter a backslash */
     g++;/* g now points to a brace */					
   }									
   FudgeStrWidth(obj[curobj]);
   (obj[curobj])->un.text.StrPtr[g] = '\0';				
   /*  zapped */							
   (obj[curobj])->from[ypt] -=						
 	k * NewLineSpacingMul * 					
		CMPT * charheight(p->un.text.font);			
   return(g);
}

SpecialSpecial()
{
   switch (Special)
   {
	case grk:
	   (obj[curobj])->un.text.Sp = grk;
	   (obj[curobj])->un.text.FF = Greek;
	break;
	case pls:
	   (obj[curobj])->un.text.Sp = pls;
	   (obj[curobj])->un.text.fontsize -= SuScriptSm;
	   if ((obj[curobj])->un.text.fontsize < 3)
	   	(obj[curobj])->un.text.fontsize = 3;
	   (obj[curobj])->un.text.up = 
		SupAboveText * CMPT * charheight((obj[curobj])->un.text.font);
	break;
	case mns:
	   (obj[curobj])->un.text.Sp = mns;
	   (obj[curobj])->un.text.fontsize -= SuScriptSm;
	   if ((obj[curobj])->un.text.fontsize < 3)
	   	(obj[curobj])->un.text.fontsize = 3;
	   (obj[curobj])->un.text.up = 
		SubBelowText * CMPT * charheight((obj[curobj])->un.text.font);
	break;
	default:
		fprintf(stderr,"splot error: strange special type\n");
	break;
   }
}

FudgeStrWidth(p) /* adjusts for str width if not left justified */
  LocalObjectType *p;
{
int i = 0;
int gcnt = 0;
int cnt = 0;
boolean PastSp = FALSE;
/* looks for first \n or \0 ands stops */
	while ((p->un.text.StrPtr[i] != '\0')&&
	       (p->un.text.StrPtr[i] != '\n')&&
	       (!(
		  (p->un.text.StrPtr[i] == '\\')&&
		  (p->un.text.StrPtr[i+1] == 'n')
	       ))
	      )
	{
		if (p->un.text.StrPtr[i] == '\n')
		{
			if (gcnt < cnt) gcnt = cnt;
			cnt = 0;
			PastSp = FALSE;
			i++;
		}
		else if 
		    (
		     (p->un.text.StrPtr[i] == '\\')&&
		     (p->un.text.StrPtr[i+1] == 'n')
		    )
		{
			if (gcnt < cnt) gcnt = cnt;
			cnt = 0;
			PastSp = FALSE;
			i++;i++;
		}
		else if 
		   (
		    (p->un.text.StrPtr[i] == '\\') &&
		    (p->un.text.StrPtr[i+1] != '\\')
		   )
		{
			PastSp = TRUE;
			i++;i++;i++;
		}
		else if (PastSp) 
		{
			if (p->un.text.StrPtr[i] != '}')
				cnt++;
			i++;
		}
		else
			i++;
	}
	if (gcnt < cnt) gcnt = cnt;

        if (p->scale)
	{
		scaleobj(p);
		p->scale = FALSE;
	}
       	switch( p->un.text.align )
        {
	 case left:
	   break;
	 case center:
		p->from[xpt] -= 
		  cos(DEGTORAD * p->un.text.angle) 
		     * (gcnt * CMPT * charwidth(p->un.text.font) / 2);
		p->from[ypt] -= 
		  sin(DEGTORAD * p->un.text.angle) 
		     * (gcnt * CMPT * charwidth(p->un.text.font) / 2);
	   break;
	 case right:
		p->from[xpt] -= 
		  cos(DEGTORAD * p->un.text.angle) 
		     * (gcnt * CMPT * charwidth(p->un.text.font));
		p->from[ypt] -= 
		  sin(DEGTORAD * p->un.text.angle) 
		     * (gcnt * CMPT * charwidth(p->un.text.font));
	   break;
	}
}
