********************************************************************************
* Description of the Program -												   *
* This program is used to set theme values for things like backgrounds, point  *
* sizes, font sizes, etc...   The purpose is to allow the end user greater	   *
* flexibility in developing graph themes (e.g., create a ggplot2 theme with    *
* a given set of palettes and also create a theme with a more Tufte inspired   *
* set of background/size parameters). 										   *
*                                                                              *
* Data Requirements -														   *
*	  Allows users to build the property file interactively					   *
*																			   *
* System Requirements -														   *
*     none                                                                     *
*                                                                              *
* Program Output -                                                             *
*     theme-[theme file name].theme - The theme file created by the user	   *
*	  theme-[theme file name]_achromatopsia.theme - Full Colorblind version	   *
*	  theme-[theme file name]_protanopia.theme - Full Colorblind version	   *
*	  theme-[theme file name]_deuteranopia.theme - Full Colorblind version	   *
*	  theme-[theme file name]_tritanopia.theme - Full Colorblind version	   *
*                                                                              *
* Lines -                                                                      *
*     391                                                                      *
*                                                                              *
********************************************************************************
		
*! brewtheme
*! v 1.0.0
*! 21MAR2016

// Drop the program from memory if loaded
cap prog drop brewtheme

// Define program
prog def brewtheme

	// Set version to interpret under
	version 13.1
	
	// Set syntax tree
	syntax [anything(name=themefile id="Theme File Name")] [,				 ///   
						ABOvebelow(string asis) ANGLESTYle(string asis)		 ///   
						AREASTYle(string asis) ARROWSTYle(string asis)		 ///   
						AXISSTYle(string asis) BARLABELPos(string asis)		 ///   
						BARLABELSTYle(string asis) BARSTYle(string asis)	 ///   
						BYGRAPHSTYle(string asis) CLEGENDSTYle(string asis)	 ///   
						CLOCKdir(string asis) COLor(string asis)			 ///   
						COMPASS2dir(string asis) COMPASS3dir(string asis)	 ///   
						CONNECTSTYle(string asis) DOTTYPESTYle(string asis)	 ///   
						GRAPHSIze(string asis) GRAPHSTYle(string asis)		 ///   
						GRIDLINESTYle(string asis) GRIDRINGSTYle(string asis) ///   
						GRIDSTYle(string asis) GSIZE(string asis) 			 ///   
						HORIZontal(string asis) LABELSTYle(string asis)		 ///   
						LEGENDSTYle(string asis) LINEPATtern(string asis)	 ///   
						LINESTYle(string asis) LINEWidth(string asis)		 ///   
						MARGin(string asis) MEDTYPESTYle(string asis)		 ///   
						NUMSTYle(string asis) NUMTICKS(string asis)			 ///   
						PIEGRAPHSTYle(string asis) PIELABELSTYle(string asis) ///   
						PLOTREGIONSTYle(string asis) RELATIVEPos(string asis) ///   
						RELSIze(string asis) SPECial(string asis)			 ///   
						STARSTYle(string asis) SYMBol(string asis)			 ///   
						SYMBOLSIze(string asis) SUNFLOWERSTYle(string asis)	 ///   
						TEXTBOXSTYle(string asis) TICKPosition(string asis)  ///   
						TICKSTYle(string asis) TICKSETSTYle(string asis)	 ///   
						VERTICALText(string asis) YESNo(string asis) 		 ///   
						ZYX2Rule(string asis) ZYX2STYle(string asis) 		 ///   
						LOADThemedata brewscheme ]
						
	// Check for brewscheme Mata library
	qui: brewlibcheck
	
	// Stores the root file path for theme files
	loc themeroot `c(sysdir_personal)'b/theme/theme
	
	// Preserve the current state of the data	
	preserve	
	
		// Only initialize this mata class if program not called by brewscheme
		if `"`brewscheme'"' == "" {
		
			// Create a brewcolors object
			mata: brewc = brewcolors()

		} // End IF Block to initialize brewcolors object	
			
		// Get the list of unique meta names
		qui: mata: brewc.getNames(1, 1)
		
		// Build dataset with classes, arguments, and parameter values
		qui: themedata
		
		// Store the name of the tempfile 
		loc tmptheme `r(themefile)'
		
		// Load the tempfile
		qui: use `tmptheme', clear
		
		// Loop over the class names
		foreach v in `"`r(classes)'"' {
		
			// Store arguments in new locals
			loc `v'args `"`r(``v'args')'"'
			
			// If the user passed values
			if `"``v''"' != "" {
			
				// Loop over arguments
				forv i = 1/`: word count ``v''' {
				
					// Store argument
					loc indi `: word `i' of ``v'''
				
					loc arg `: word 1 of `indi''
					
					loc val `: word 2 of `indi''
					
					// Block used to handle cases with unbalanced quotation marks
					// in the value of the key-value pair.
					if 	substr(`"`val'"', 1, 1) != `"""' & 					 ///   
						substr(`"`val'"', -1, 1) == `"""' {
						
						// If the first character isn't a " but the last 
						// character is a " replace all instances of " with 
						// nothing in the value string
						loc val `: subinstr loc val `"""' "", all'

					} // End IF Block for unbalanced quotation mark handling
					
					// Check if valid argument
					if `"`: list arg in `v'args'"' != "" {

						// Search for the RGB values
						qui: mata: brewc.brewNameSearch("`val'")
						
						foreach x in rgb achromatopsia protanopia deuteranopia tritanopia { 
						
							if `"``x''"' == "" loc `x' none
							
						}
						
						// Check for named color style
						if `: list val in colornames' == 1 {
							
							// Replace value with user specified value
							qui: replace value = `"`val'"' if 				 ///   
							classname == `"`v'"' & argname == `"`arg'"'
							
							// Populate color blind variables
							qui: replace achromatopsia = `"`val'_achromatopsia"' ///   
							if classname == `"`v'"' & argname == `"`arg'"'

							// Populate red colorblindness 
							qui: replace protanopia = `"`val'_protanopia"' if	 ///   
							classname == `"`v'"' & argname == `"`arg'"'
							
							// Populate red colorblindness 
							qui: replace deuteranopia = `"`val'_deuteranopia"' ///   
							if classname == `"`v'"' & argname == `"`arg'"'
							
							// Populate red colorblindness 
							qui: replace tritanopia = `"`val'_tritanopia"' if	 ///   
							classname == `"`v'"' & argname == `"`arg'"'
							
						} // End IF Block for color value
											
						// Check to see if the value was a color
						else if `"`val'"' != `"`rgb'"' &					 ///   
						`: list val in colornames' == 0 {
							
							// Replace value with user specified value
							qui: replace value = `""`rgb'""' if 			 ///   
							classname == `"`v'"' & argname == `"`arg'"'
							
							// Populate color blind variables
							qui: replace achromatopsia = `""`achromatopsia'""' ///   
							if classname == `"`v'"' & argname == `"`arg'"'

							// Populate red colorblindness 
							qui: replace protanopia = `""`protanopia'""' if	 ///   
							classname == `"`v'"' & argname == `"`arg'"'
							
							// Populate red colorblindness 
							qui: replace deuteranopia = `""`deuteranopia'""' ///   
							if classname == `"`v'"' & argname == `"`arg'"'
							
							// Populate red colorblindness 
							qui: replace tritanopia = `""`tritanopia'""' if	 ///   
							classname == `"`v'"' & argname == `"`arg'"'
							
						} // End ELSEIF Block for color value
						
						// For non color values
						else {
						
							// Replace value with user specified value
							qui: replace value = `"`rgb'"' if 				 ///   
							classname == `"`v'"' & argname == `"`arg'"'
							
							// Populate color blind variables
							qui: replace achromatopsia = `"`achromatopsia'"' ///   
							if classname == `"`v'"' & argname == `"`arg'"'

							// Populate red colorblindness 
							qui: replace protanopia = `"`protanopia'"' if	 ///   
							classname == `"`v'"' & argname == `"`arg'"'
							
							// Populate red colorblindness 
							qui: replace deuteranopia = `"`deuteranopia'"' if ///   
							classname == `"`v'"' & argname == `"`arg'"'
							
							// Populate red colorblindness 
							qui: replace tritanopia = `"`tritanopia'"' if	 ///   
							classname == `"`v'"' & argname == `"`arg'"'
													
						} // End ELSE Block for non color values
										
					} // End IF Block for valid arguments
									
				} // End Loop over arguments
			
			} // End IF Block for user supplied values
			
		} // End Loop over class names
		
		// Save changes to the tempfile
		qui: save `tmptheme', replace
		
		// Check for name of themefile
		if `"`themefile'"' != "" {

			// Check for directory and if not build it	
			dirfile, p(`"`c(sysdir_personal)'b/theme"') 
			
			// Write the scheme file to a location on the path
			qui: file open theme using `"`themeroot'-`themefile'.theme"', w replace
				
			// Loop over colorblind variables
			foreach cb in achromatopsia protanopia deuteranopia tritanopia {

				// Open a theme file for each of the colorblind types
				qui: file open `cb'theme using 								 ///   
				`"`themeroot'-`themefile'_`cb'.theme"', w replace
			
			} // End Loop to open color blindness theme files
			
			// Call write subroutine
			themewriter

		} // End IF BLock for writing a theme file if user specified a theme file name
		
		// If no name is passed write the default file
		else {
		
			// Check for directory and if not build it	
			dirfile, p(`"`c(sysdir_personal)'b/theme"') 
			
			// Write the scheme file to a location on the path
			qui: file open theme using `"`themeroot'-default.theme"', w replace
				
			// Loop over colorblind variables
			foreach cb in achromatopsia protanopia deuteranopia tritanopia {

				// Open a theme file for each of the colorblind types
				qui: file open `cb'theme using 								 ///   
				`"`themeroot'-default_`cb'.theme"', w replace
			
			} // End Loop to open color blindness theme files
			
			// Call write subroutine
			themewriter

		} // End else block for a default theme file
	
	// Restore the data to the original state
	restore
	
	// Check loadthemedata option
	if `"`loadthemedata'"' != "" {
	
		// Load the tempfile
		qui: use `tmptheme', clear
		
	} // End IF Block for load theme data option
	
// End Program Definition	
end

// Drop subroutine if already loaded in memory
cap prog drop themedata
	
// Subroutine to build look up dataset
prog def themedata, rclass

	// Null syntax structure
	syntax 

	// Drop data from memory
	clear 
	
	// Check for file
	cap confirm file `"`c(sysdir_plus)'b/brewthemedata.do"'
	
	// If does not exist
	if _rc != 0 { 
	
		// Download the file from GitHub
		copy "http://wbuchanan.github.io/brewscheme/brewthemedata.do" 		 ///   
		`"`c(sysdir_plus)'b/brewthemedata.do"'
		
	} // End IF Block for non-existent file

	// Run the do file
	qui: do `"`c(sysdir_plus)'b/brewthemedata.do"'

	// Reserve namespace for a temporary file
	tempfile themedata

	// Get the names of the classes that can have values altered
	qui: levelsof classname if substr(classname, 1, 1) != "*", loc(classes) 

	// Return a local with the class names
	ret loc classes `classes'

	// Loop over the class names
	foreach v of loc classes {

		// Get the argument names for the classes
		qui: levelsof argname if classname == `"`v'"', loc(args) 
		
		// Return the arguments for the given class
		ret loc `v'args `args'
		
	} // End Loop over the class names

	// Save the data to a temporary file
	qui: save `themedata'.dta, replace

	// Clear those data from memory
	clear

	// Return the name of the tempfile 
	ret loc themefile `themedata'.dta

// End of the subroutine definition
end

// Drop subroutine if already loaded in memory
cap prog drop themewriter
	
// Subroutine for writing the data to a theme file
prog def themewriter

	// Null syntax structure
	syntax 

	// Loop over the observations
	forv i = 1/`c(N)' {
	
		// Combine the different variables into a single string
		loc string `: di classnm[`i'] + argnm[`i'] + value[`i']'
		
		// Write the string to the file and insert the number of new 
		// lines based on new line variable
		file write theme `"`"`string'"' `: di newlines[`i']'"' _n
		
		// Loop over the colorblindness types
		foreach cb in achromatopsia protanopia deuteranopia tritanopia {
			
			// Creates string with color bli
			loc string `: di classnm[`i'] + argnm[`i'] + `cb'[`i']'
			
			// Write to the colorblind simulated theme file
			file write `cb'theme `"`"`string'"' `: di newlines[`i']'"' _n
			
		} // End Loop over colorblind transformed theme files
			
	} // End Loop over observations
	
	// Close the open file connection
	file close theme
	
	// Loop over the colorblindness types
	foreach cb in achromatopsia protanopia deuteranopia tritanopia {
			
		// Close the theme file
		file close `cb'theme
		
	} // End loop over colorblindness type theme files
			
// End of sub routine
end