//////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
//
//	Script By Mohannad Al-Khatib 
//
//////////////////////////////////////////////////////////////////////////////////////

//global variables 
 global string $globLsys[];	 //array of the L-sys levels 
 clear ($globLsys);		 //clears it in case it was left over from a previous usage of teh script 
 global int $globDepth ;	


 global string $globDefinedNames[];	
 clear ($globDefinedNames);
 global int $globDefinedNamesIndex =0 ;

 global int $layerCreated = 0;	// to be used as a boolean

//main UI proc
global proc UI(){

scriptEditorInfo -ch;	//clear the history in the script editor [keeps it clean for easier debugging]
window -rtf true -title "Create an Lsystem pattern" -width 400 qqqq;	//create a window 

columnLayout;
textFieldGrp -label "Intial Word" -cw 1 100  intialWord;

textFieldGrp -label "Rule1" -w 160 r1;
textFieldGrp -label "Result1" -w 400 res1;

textFieldGrp -label "Rule2" -w 160 r2;
textFieldGrp -label "Result2" -w 400 res2;

textFieldGrp -label "Rule3" -w 160 r3;
textFieldGrp -label "Result3" -w 400 res3;

textFieldGrp -label "Rule4" -w 160  r4;
textFieldGrp -label "Result4" -w 400 res4;

intSliderGrp -label "depth" -field true -maxValue 10 -minValue 1 -v 3  depth;
intSliderGrp -label "Max length" -field true -maxValue 3000 -v 1000 msize;

button -c "generator" -label "Generate" -w `window -q -w qqqq`;	//a button that calls the generator proc

textField  -ed false -tx "Preview: no L-system has been generated yet!" -w `window -q -w qqqq`  lSysOut; //a text feild for the Lsys preview

button -c "defineUI" -label "Define selected object(s) as a Character" -w `window -q -w qqqq`; //a button that calls the DefineUI proc
button -c "visualUI" -label "Visualiztion" -w `window -q -w qqqq`;				//a button that calls the visualUI proc

showWindow qqqq;		//show the window
}



global proc generator (){
 
  global string $globLsys[];	//redefine the global vars in order to gain access to them
  global int $globDepth ;

 
//capture the input from the main UI window into vars
$wordd = `textFieldGrp -q  -tx "intialWord"`;
$globDepth = `intSliderGrp -q  -value "depth"`;
int $msize = `intSliderGrp -q  -value "msize"`;

$r1 = startString(`textFieldGrp -q  -tx "r1"`, 1);
$r2 = startString(`textFieldGrp -q  -tx "r2"`, 1);
$r3 = startString(`textFieldGrp -q  -tx "r3"`, 1);
$r4 = startString(`textFieldGrp -q  -tx "r4"`, 1);

$res1 =`textFieldGrp -q  -tx "res1"`;
$res2 =`textFieldGrp -q  -tx "res2"`;
$res3 =`textFieldGrp -q  -tx "res3"`;
$res4 =`textFieldGrp -q  -tx "res4"`;



 string $temp;		//a temporary string for the lsys to be constructed in before copying it into the main lsys array
 $globLsys[0] = $wordd; //1st level is the intial word
 string $char;		//a cariable to store the current character in as the generator go over the rules.. 

   for ($i=0; $i <$globDepth; $i++){
   $temp="";				//reset the temp
	   for ($ii=0; $ii <=size($globLsys[$i]); $ii++){	

		//store the caracter in the $char var.. [this is a trick i had to think of since there is no charAt function.. 
		//it takes the 1st $ii characters of the string then takes the last 1.. 
		$char =endString(startString($globLsys[$i],$ii),1); 

		//check the rules for a match.. or just add that char as it is.. 
		if($char== $r1 && $r1 !=""){
			$temp =  $temp + $res1;
		}
		
		else if($char== $r2 && $r2 !=""){
			$temp =  $temp + $res2;
		}

		else if($char== $r3 && $r3 !=""){
			$temp =  $temp + $res3;
		}

		else if($char== $r4 && $r4 !=""){
			$temp =  $temp + $res4;
		} else {
			$temp =  $temp  +$char;
		}
		
		$globLsys[$i+1] = $temp; //store that temp into the main array
		
	   }
	   print ("\n"+"level "+$i+": "+$temp);	//output the current level .. "\n" = new line
      }

print ("\n"+$globLsys[$globDepth]);	//output the final lsys
$globLsys[$globDepth] = endString($globLsys[$globDepth],$msize); //limit the size of the final string to stay under the limit set by the user

textField  -e  -tx ("["+size($globLsys[$globDepth])+"] "+$globLsys[$globDepth]) lSysOut; //send the lsys to be previewed in the texfeild
}

//the definition UI
global proc defineUI(){

 global int $layerCreated;	//redefine global vars to gain access to them

// if the layers haven't been created create them
if ($layerCreated !=1){
createDisplayLayer -name "Lsys_templates" -noRecurse  -number 9 ;
createDisplayLayer -name "Lsys_outcome" -noRecurse  -number 9 ;
$layerCreated = 1;
}

window -rtf true -title "Create an Lsystem pattern" -width 400 dd; //create a window

columnLayout;
textFieldGrp -label "Character"  charname;

button -c "define" -label "Define" -w `window -q -w dd`;	//a button the calls teh define proc 

textField  -ed false -tx "select the object(s) and type 1 character only, the rest will be ingored." -w `window -q -w dd`  defineHelp;
showWindow dd;
}

//the define proc 
global proc define (){

 global string $globDefinedNames[];	//redefine global vars to gain access to them
 global int $globDefinedNamesIndex =0 ;

 int $existingName=0;	//to be used as a boolean
 string $name =startString(`textFieldGrp -q  -tx "charname"`, 1); //capture the name from thee UI

 string $objects[] =`ls- dag`;				//list all the objects in the scene

	for ($i=0; $i<size($globDefinedNames); $i++){	//check if thr name name has been assigned by this script or not

		if ($name==$globDefinedNames[$i]){
			$existingName =1;
		}else {
			$existingName =0;
		}
	}

	if ($name!="" && $existingName ==0){		//if the name the user is trying to assign is not empty  and the name 
		
		for ($ii=0; $ii<size($objects); $ii++){ //look through the list of the objects in the scene 
			if ($name == $objects[$ii]){    //and if theres an object wtith that name that has not been assigned bu this script .. rename it 
			rename  $objects[$ii] ($name+$name);
			}
		}
			
		group;			//group the selected object(s)
		rename ($name);		//rename them
		editDisplayLayerMembers Lsys_templates `ls -selection`; // add the whats seleced [the renamed group] in the template layer

		$globDefinedNames[$globDefinedNamesIndex]=$name;         
		$globDefinedNamesIndex++;

		textField  -e  -tx "Object(s) defined." defineHelp;  //send a msg to the text output
		textFieldGrp  -e  -tx "" charname;		     //reset the text feild

	} else if ($existingName==1){				     //if the name already exists send an error msg to the text output
		textField  -e  -tx "Error: please type a unique Character or delete the group wiith that name" defineHelp;
	} else {						     //otherwise the text feild must've been empty.. send the error msg to the textfeild
		textField  -e  -tx "Error: please type a Character" defineHelp;
	}
}


//the visualiztion UI 
global proc visualUI(){
window -rtf true -title "Create an Lsystem pattern" -width 400 v; // create a window 

columnLayout;
floatSliderGrp -label "virtical spacing" -field true  -v 0.3  spacing;
intSliderGrp -label "rotation angle" -field true -maxValue 360 -minValue -360 -v 45  rotation;
button -c "visual" -label "visualize" -w `window -q -w v`; //a button that calls the visual proc

showWindow v;	//show the window 

}


global proc visual (){

 global string $globLsys[];	//redefine the global cars to gain access to them
 global int $globDepth ;

 global string $globDefinedNames[];
 global int $globDefinedNamesIndex;

 float $spacing = `floatSliderGrp -q  -value "spacing"`;	//capture the input from the UI
 int $rotation = `intSliderGrp -q  -value "rotation"`;

 layerEditorSelectObjects Lsys_outcome;	//select what on the outcome layer 
 delete;				//and delete it [undoing the previous visualiztion]

 string $selection[] = `ls -sl`;	//list selection in an array
 string $char;

	for ($ii=1; $ii <=size($globLsys[$globDepth]); $ii++){			//go through the lsys
		$char = endString(startString($globLsys[$globDepth],$ii),1);	//and store the currect char temporarily

		for ($i=0; $i <=$globDefinedNamesIndex; $i++){			//go through the defined names
			
			  if($char == $globDefinedNames[$i]){			//if the char matches a name
				select -r $char;				//select the object with that name 
				instance;					//create an instance of it 
				move -os 0 ($spacing*$ii) 0;			//move it along the the Y axis 
				editDisplayLayerMembers Lsys_outcome `ls -selection`;	//add it to the outcome layer
				xform -os -piv 0 0 0;				//reset the pivot point to the center
				rotate -os 0 ($rotation*$ii) 0 ;		//rotate it
				editDisplayLayerMembers Lsys_templates $char;	//add the original object back to the templates layer
				print ("\n"+"processing: "+$ii+"/"+size($globLsys[$globDepth]));	//print out the process 
			   }
		
		}

	}

}