#!NOMODULE
#define max(i, j) (((i)>(j)) ? (i) : (j))
#define min(i, j) (((i)<(j)) ? (i) : (j))
#define abs(arg) ((arg)*(1-2*((arg)<0)))

#define PI 3.14159265358979

import Image;
import Array;
import Stdio;
inherit "polyline.pike";
constant LITET = 1.0e-40;
constant STORT = 1.0e40;

inherit "create_graph.pike";
inherit "create_bars.pike";

constant cvs_version = "$Id: create_pie.pike,v 1.29 1997/12/03 23:02:00 hedda Exp $";

/*
These functions is written by Henrik "Hedda" Wallin (hedda@idonex.se)
Create_pie can draw pie charts in different forms.

The data is taken from the diagram_data-mapping which is described in doc/diagram_internals.txt


*/ 




mapping(string:mixed) create_pie(mapping(string:mixed) diagram_data)
{
  //Only tested with xsize>=100
  int si=diagram_data["fontsize"];

  string where_is_ax;

  object(image) piediagram;

  init_bg(diagram_data);
  piediagram=diagram_data["image"];
  setinitcolors(diagram_data);

  set_legend_size(diagram_data);

  diagram_data["ysize"]-=diagram_data["legend_size"];
  
  //Do the standard init (The init function is in create_graph)
  init(diagram_data);

  //Initiate values
  int|void  size=diagram_data["xsize"];
  array(int|float) numbers=diagram_data["data"][0];
  void | array(string) names=diagram_data["xnames"];
  void|int twoD=diagram_data["drawtype"]=="2D";
  void|array(array(int)) colors=diagram_data["datacolors"];
  array(int)bg=diagram_data["bgcolor"];
  array(int)fg=diagram_data["textcolor"];
  int tone=diagram_data["tone"];

  for(int i; i<sizeof(numbers); i++)
    if ((float)numbers[i]<0.0)
      numbers[i]*=-1.0;
  



  //////////////////////



  
  object* text;
  object notext;
  int ymaxtext;
  int xmaxtext;

  int imysize;
  int imxsize;
  float *arr=allocate(802);
  float *arr2=allocate(802);

  int yc;
  int xc;
  int xr;
  int yr;

  mixed sum;
  int sum2;

  int* pnumbers=allocate(sizeof(numbers));
  int* order=indices(numbers);

  int edge_nr=0;



  //create the text objects
  if (names)
    text=allocate(sizeof(names));
   
  if (diagram_data["3Ddepth"]>diagram_data["ysize"]/5)
    diagram_data["3Ddepth"]=diagram_data["ysize"]/5;

  if (names)
    if (notext=get_font("avant_garde", diagram_data["fontsize"], 0, 0, "left",0,0))
      for(int i=0; i<sizeof(names); i++)
	{
	  if ((names[i]!=0) && (names[i]!=""))
	    text[i]=notext->write((string)(names[i]))
	      ->scale(0,diagram_data["fontsize"]);
	  else
	    text[i]=image(diagram_data["fontsize"],diagram_data["fontsize"]);

	  if (text[i]->xsize()<1)
	    text[i]=image(diagram_data["fontsize"],diagram_data["fontsize"]);

	  if (text[i]->xsize()>diagram_data["xsize"]/5+diagram_data["3Ddepth"])
	    text[i]=text[i]->scale((int)diagram_data["xsize"]/5, 0);

	  if (text[i]->ysize()>diagram_data["ysize"]/5-diagram_data["3Ddepth"])
	    text[i]=text[i]->scale(0, (int)diagram_data["ysize"]/5-
				   diagram_data["3Ddepth"]);
	  
	  if (xmaxtext<(text[i]->xsize()))
	    xmaxtext=text[i]->xsize();
	  if (ymaxtext<(text[i]->ysize()))
	    ymaxtext=text[i]->ysize();
	  
	}

  //Some calculations
  if (twoD)
    {
      xc=diagram_data["xsize"]/2;
      yc=diagram_data["ysize"]/2;
      xr=(int)min(xc-xmaxtext-ymaxtext-1-diagram_data["linewidth"], 
		  yc-2*ymaxtext-1-diagram_data["linewidth"]);
      yr=xr;
    }
  else
    {
      xc=diagram_data["xsize"]/2;
      yc=diagram_data["ysize"]/2-diagram_data["3Ddepth"];
      yr=(int)(min(xc-xmaxtext-ymaxtext-1-diagram_data["3Ddepth"], yc-2*ymaxtext-1)
	       -diagram_data["linewidth"]);
      xr=(int)(min(xc-xmaxtext-ymaxtext-1, yc+diagram_data["3Ddepth"]-2*ymaxtext-1)-
	       diagram_data["linewidth"]);
    }
  float w=diagram_data["linewidth"];


  //initiate the 0.25*% for different numbers:
  //Ex: If numbers is ({3,3}) pnumbers will be ({200, 200}) 
  sum=`+(@ numbers);
  int i;

  if (sum>LITET)
    {
      for(int i=0; i<sizeof(numbers); i++)
	{
	  float t=(float)(numbers[i]*400)/sum;
	  pnumbers[i]=(int)floor(t);
	  numbers[i]=t-floor(t);
	}
      
      
      //Now the rests are in the numbers-array
      //We now make sure that the sum of pnumbers is 400.
      sort(numbers, order);
      sum2=`+(@ pnumbers);
      i=sizeof(pnumbers);
      while(sum2<400)
	{
	  pnumbers[order[--i]]++;
	  sum2++;
	}  
    }
  else
    if (sizeof(numbers)>1)
      {
	for(int i=0; i<sizeof(numbers); i++)
	  pnumbers[i]=(int)floor(400.0/(float)sizeof(numbers));
	int j=400-`+(@pnumbers);
	for(int i=0; i<j; i++)
	  pnumbers[i]++;
      }
    else
      pnumbers=({400});
  
  //Initiate the piediagram!
  float FI=0;
  if (diagram_data["center"])
    {
      //If to great center integer is given, module is used. 
      // Center should not be greater than sizeof(data[0]).
      diagram_data["center"]%=(1+sizeof(numbers));
      FI=(400-`+(0,@pnumbers[0..diagram_data["center"]-2])
	-pnumbers[diagram_data["center"]-1]*0.5)*2.0*PI/400.0;
    }
  else
    if (diagram_data["rotate"])
      FI=((float)(diagram_data["rotate"])*2.0*PI/360.0)%(2*PI);
  float most_down=yc+yr+w;
  float most_right=xc+xr+w;
  float most_left=xc-xr-w;

  for(int i=0; i<401; i++)
    {
      arr[2*i]=xc+xr*sin((i*2.0*PI/400.0)+FI);
      arr[1+2*i]=yc+yr*sin(-PI/2+i*2.0*PI/400.0+FI);
      arr2[2*i]=xc+(xr+w)*sin((i*2.0*PI/400.0));
      arr2[2*i+1]=yc+(w+yr)*sin(-PI/2+i*2.0*PI/400.0);
    }

  //Draw the slices
  if (sizeof(diagram_data["datacolors"])>
      sizeof(diagram_data["data"][0]))
    diagram_data["datacolors"]=diagram_data["datacolors"]
      [0..sizeof(diagram_data["data"][0])-1];
  
  int t=sizeof(diagram_data["datacolors"]);

  edge_nr=0;
  for(i=0; i<t; i++)
    {
      piediagram=piediagram->setcolor(@diagram_data["datacolors"][i]);
      if (pnumbers[i])
	piediagram=piediagram->polygone(({(float)xc,(float)yc})+
					arr[2*edge_nr..2*(edge_nr+pnumbers[i]+2)+1]);
      edge_nr+=pnumbers[i];
    }
  


  edge_nr=pnumbers[0];


  //black borders
  if (diagram_data["linewidth"]>LITET)
    {
      piediagram=piediagram->setcolor(@diagram_data["axcolor"]);
      piediagram=piediagram->polygone(
				      make_polygon_from_line(diagram_data["linewidth"],
							     ({
							       xc,
							       yc,
							       arr[0],
							       arr[1]
							     })
							     ,
							     0, 1)[0]
				      );

      for(int i=1; i<sizeof(pnumbers); i++)
	{
	  piediagram=piediagram->
	    polygone(
		     make_polygon_from_line(diagram_data["linewidth"],
					    ({xc
					      ,yc,
					      arr[2*(edge_nr)],
					      arr[2*(edge_nr)+1]
					    })
					    ,
					    0, 1)[0]
		     );
	  
	  edge_nr+=pnumbers[i];
	}
      piediagram=piediagram->polygone(arr+arr2);
    }
  
  piediagram=piediagram->setcolor(255,255,255);
  
  //And now some shading!
  if (!twoD)
    {
      object below;
      int *b=({70,70,70});
      int *a=({0,0,0});
      
      
      object tbild;
      /*
	tbild=image(imxsize, 1, 255, 255, 255)->
	tuned_box(0, 0 , 1, imysize,
	({a,a,b,b}))->scale(imxsize, imysize);
	//400ms
	*/
      int imxsize=piediagram->xsize(); //diagram_data["xsize"];
      int imysize=piediagram->ysize(); //diagram_data["ysize"]+diagram_data["legendsize"];

      if(tone)
	{
	  
	  
	  tbild=image(imxsize, imysize, 255, 255, 255)->
	    tuned_box(0, 0 , 1, imysize,
		      ({a,a,b,b}));
	  tbild=tbild->paste(tbild->copy(0,0,0, imysize), 1, 0);
	  tbild=tbild->paste(tbild->copy(0,0,1, imysize), 2, 0);
	  tbild=tbild->paste(tbild->copy(0,0,3, imysize), 4, 0);
	  tbild=tbild->paste(tbild->copy(0,0,7, imysize), 8, 0);
	  tbild=tbild->paste(tbild->copy(0,0,15, imysize), 16, 0);
	  if (imxsize>32)
	    tbild=tbild->paste(tbild->copy(0,0,31, imysize), 32, 0);
      
	  if (imxsize>64)
	    tbild->
	      paste(tbild->copy(0,0,63, imysize), 64, 0);
	  if (imxsize>128)
	    tbild=tbild->paste(tbild->copy(0,0,128, imysize), 128, 0);
	  if (imxsize>256)
	    tbild=tbild->paste(tbild->copy(0,0,256, imysize), 256, 0);
	  if (imxsize>512)
	    tbild=tbild->paste(tbild->copy(0,0,512, imysize), 512, 0);
	  piediagram+=tbild;
	}
      
      float* arr3;
      float* arr4;
      float* arr5;
      
      
      //Draw the border below.
      arr3=arr2[200..601];
      for(int i=1; i<402; i+=2)
	arr3[i]+=diagram_data["3Ddepth"];

      arr4=arr3[0..200];
      arr5=arr3[0..200];
      for(int  i=0; i<201; i++)
	{
	  arr4[i]=arr3[i*2];
	  arr5[i]=arr3[i*2+1];
	}
      arr4=reverse(arr4);
      arr5=reverse(arr5);
      int j=0;

      for(int i=0; i<201; i++)
	{
	  arr3[j++]=arr4[i];
	  arr3[j++]=arr5[i];
	}

      array(float) arr6=arr3+arr2[200..601];

      float plusx=ceil(2-(float)most_left);
      float plusy=ceil(2-(float)yc);
      for(int i=0; i<sizeof(arr6); )
	{
	  arr6[i++]+=plusx;
	  arr6[i++]+=plusy;
	}
      /*
      arr6=allocate(804);
      for(int i=0; i<201; i++)
	{
	  int j=i+200;
	  arr6[2*i]=2+(xr+w)+(xr+w)*sin((j*2.0*PI/400.0+0.0001));
	  arr6[2*i+1]=2+(w+yr)*sin(0.0001-PI/2+j*2.0*PI/400.0);

	  arr6[802-2*i]=arr6[2*i];
	  arr6[802-2*i+1]=diagram_data["3Ddepth"]+arr6[2*i+1];
	}
      */
      imxsize=(int)(ceil(most_right+4)+floor(-most_left));
      imysize=(int)(diagram_data["3Ddepth"]+yr+4);
      if (imxsize<2)
	imxsize=2;
      if (imysize<2)
	imysize=2;


      below=image(imxsize, imysize, 0, 0, 0)->
	setcolor(255,255,255)->
	polygone(arr6);
      
      b=({155,155,155});
      a=({100,100,100});
      
      object tbild;
      tbild=image(imxsize,imysize , 255, 255, 255)
	->tuned_box(0,0, imxsize/2, 1,
		  ({a,b,a,b}))
	->tuned_box(imxsize/2, 0,imxsize , 1,
		    ({b,a,b,a}));
      tbild=tbild->paste(tbild->copy(0,0,imxsize, 0),0, 1);
      
      tbild=tbild->paste(tbild->copy(0,0,imxsize, 1),0, 2);
      tbild=tbild->paste(tbild->copy(0,0,imxsize, 3),0, 4);
      tbild=tbild->paste(tbild->copy(0,0,imxsize, 7),0, 8);
      tbild=tbild->paste(tbild->copy(0,0,imxsize, 15),0, 16);
      if (tbild->ysize()>32)
	tbild=tbild->paste(tbild->copy(0,0,imxsize, 31),0, 32);
      if (tbild->ysize()>64)
	tbild=tbild->paste(tbild->copy(0,0,imxsize, 63),0, 64);
      if (tbild->ysize()>128)
	tbild=tbild->paste(tbild->copy(0,0,imxsize, 127),0, 128);
      if (tbild->ysize()>256)
	tbild=tbild->paste(tbild->copy(0,0,imxsize, 255),0, 256);
      if (tbild->ysize()>512)
	tbild=tbild->paste(tbild->copy(0,0,imxsize, 511),0, 512);
      

      //piediagram=
      piediagram->paste_mask(tbild, below, -(int)ceil(plusx), -(int)ceil(plusy) );
      
      
      
    }

  
  //write the text!
  int|float place;
  sum=0;
  if (names)
    for(int i=0; i<sizeof(text); i++)
      {
	int t;
	sum+=pnumbers[i];
	place=sum-pnumbers[i]/2;
	if (FI)
	  {
	    place=place+FI*400.0/(2.0*PI);
	    if (place>400)
	      place=place%400;
	  }
	piediagram=piediagram->setcolor(255,0, 0);

	
	t=(place<202)?0:-text[i]->xsize();
	//if (place<20) t-=7;
	//else if (place>380) t+=7;
	//else if ((place>180)&&(place<202)) t-=7;
	//else if ((place>=202)&&(place<220)) t+=7;
	//if ((place>190)&&(place<202)) t-=4;
	//if ((place>=202)&&(place<210)) t+=4;
	//if (place<10) t-=4;
	//if (place>390) t+=4;
	
	//int yt=0;
	//if ((place>120)&&(place<280))
	//  yt=(int)(34*sin(2*PI*(float)(place-100)/400.0));
	//if ((place<=80)||(place>=320)) yt-=ymaxtext;
	//else
	//  if (!((place>=120)&&(place<=280))) yt-=ymaxtext/2;
	int yt=0;
	if (((place>100)&&(place<300))&&
	    (!twoD))
	  yt=diagram_data["3Ddepth"];
	
	int ex=text[i]->ysize();
	int x=(int)(xc +t+ (xr+ex)*sin(place*PI*2.0/400.0+0.0001));
	int y=(int)(-text[i]->ysize()/2+yc +yt+ 
		    (yr+ex)*sin(-PI/2.0+place*PI*2.0/400.0+0.0001));
      

	//int x=(int)(arr2[2*place]+t);
	//int y=(int)arr[2*place+1]+yt;
	piediagram=piediagram->paste_alpha_color(text[i], @fg, x, y);
      }








  //////////////////////

  /*
  piediagram=image(diagram_data["xsize"],
		   diagram_data["ysize"]+diagram_data["legend_size"], 
		   @diagram_data["legendcolor"])->paste(piediagram->scale(diagram_data["xsize"],diagram_data["ysize"]));

  diagram_data["image"]=piediagram;
  set_legend_size(diagram_data);
  */

  diagram_data["ysize"]-=diagram_data["legend_size"];
  diagram_data["image"]=piediagram;
  return diagram_data;



}
