********************************************************************************
* Description of the Program -												   *
* This program is used to preview combinations of color palettes along with    *
* combinations created by different numbers of colors.						   *
*                                                                              *
* Lines -                                                                      *
*     461                                                                      *
*                                                                              *
********************************************************************************

*! brewviewer
*! v 1.0.0
*! 21MAR2016

// Drop program if already loaded in memory
cap prog drop brewviewer

// Define new program brewviewer
prog def brewviewer

	// Interpret syntax under Version 13.1
	version 13.1

	// Syntax structure for the program
	syntax anything(name=pal id="BrewScheme Color Palette") 				 ///
	[, Colors(numlist min = 1 max = 24 integer) COMBine Seq IMpaired ]

	// Check colors argument
	if "`colors'" == "" {

		// Print error message to the console
		di as err "Must supply at least a single value for the colors parameter."

		// Error out
		err 198

	} // End IF Block for invalid number of color arguments

	// Check impairment option to add subtitle to graph
	if `"`impaired'"' != "" loc xtralab `""with simulated total, red, green, and blue colorblindness""'

	// Preserve the current state of the data
	preserve

		// Load the brewscheme dataset
		qui: use `"`c(sysdir_personal)'b/brewmeta.dta"', clear

		// For single color listed
		if `: word count `colors'' == 1 {

			// Get maximum number of colors
			loc maxcol `= `colors''

			// If sequence switch is enabled
			if "`seq'" != "" {

				// Set color loop syntax
				loc colloop forv i = 3/`colors'

				// Get minimum number of colors
				loc mincol 3

				// sets of xaxis values
				loc simvals `= ((`colors' - 3) + 1)'

			} // End IF Block for sequence loop

			// If sequence switch is not enabled
			else {

				// Set color loop syntax
				loc colloop foreach i in `colors'

				// Get minimum number of colors
				loc mincol `colors'

				// Sets of xaxis values
				loc simvals = 1

			} // End ELSE Block for color loop syntax

		} // End ELSEIF Block for single color value

		// For fewer colors than palettes
		else if `: word count `colors'' < `: word count `pal'' {

			// Get maximum number of colors
			loc maxcol `= `: di max(`: subinstr loc colors `" "' `", "', all')''

			// If sequence switch is enabled
			if "`seq'" != "" {

				// Set color loop syntax
				loc colloop forv i = 3/`maxcol'

				// Get minimum number of colors
				loc mincol 3

				// sets of xaxis values
				loc simvals `= ((`maxcol' - 3) + 1)'

			} // End IF Block for sequence loop

			// If sequence switch is not enabled
			else {

				// Set color loop syntax
				loc colloop foreach i in `colors'

				// Get minimum number of colors
				loc mincol `: di min(`: subinstr loc colors `" "' `", "', all')'

				// Sets of xaxis values
				loc simvals = 1

			} // End ELSE Block for color loop syntax

		} // End ELSEIF Block for fewer colors than palettes

		// If there are more colors than palettes {
		else if `: word count `colors'' == `: word count `pal'' {

			// If sequence switch is enabled
			if "`seq'" != "" {

				// Set color loop syntax
				loc colloop forv i = 3/\`: word \`w' of `colors''

				// Get minimum number of colors
				loc mincol 3

			} // End IF Block for sequence loop

			// If sequence switch is not enabled
			else {

				// Set color loop syntax
				loc colloop foreach i in \`: word \`w' of \`colors''

				// Get minimum number of colors
				loc mincol `: di min(`: subinstr loc colors `" "' `", "', all')'

			} // End ELSE Block for color loop syntax

			// Get maximum number of colors
			loc maxcol `= `: di max(`: subinstr loc colors `" "' `", "', all')''

			// sets of xaxis values
			loc simvals `= ((`maxcol' - 3) + 1)'

		} // End ELSEIF Block for more colors than palettes

		// If there are more colors than palettes
		else {

			// Set color loop syntax
			loc colloop foreach i in `colors'

			// Get maximum number of colors
			loc maxcol `= `: di max(`: subinstr loc colors `" "' `", "', all')''

			// Get minimum number of colors
			loc mincol `: di min(`: subinstr loc colors `" "' `", "', all')'

			// sets of xaxis values
			loc simvals `= ((`maxcol' - 3) + 1)'

		} // End ELSE Block for more colors than palettes

		// Create counter for simulated values
		loc simcount = 1

		// Loop over the number of palettes passed to the main argument
		forv w = 1/`: word count `pal'' {

			// Get the palette name
			loc palnm : word `w' of `pal'

			// Get the mean from the maxcolors variable (constant by palette)
			qui: su maxcolors if palette == `"`palnm'"'

			// Set a local for maximum number of colors
			loc bkupmax `r(max)'

			// Check for colorblindness simulation option
			if `"`simcb'"' != "" loc sze `= 1.5 + `= 1/(`maxcol' * 5)''

			// Set the size of the boxes based on the log of 3 times n colors
			else loc sze `= 2 + `= 1/`maxcol'''

			// Local to build xaxis labeling rules
			loc xax

			// Initialize scatteri local macro
			loc cmd

			// Loop over the smallest number of colors available in any palettes
			`colloop' {

				// Find max colors
				qui: su maxcolors if palette == `"`palnm'"', meanonly

				// Create graph if acceptable value
				if `r(mean)' >= `i' {

					// Initialize a null macro to use like a StringBuilder class in Java
					loc scat`i'

					// Loop over the number of unique colors based on the palette color id
					forv j = 1/`i' {

						// Get the number of palette color ids
						qui: levelsof pcolor if palette == `"`palnm'"', loc(pcid)

						// Test if the value exists in the pcolor ids
						loc gmax : list i in pcid

						// If not in pcid list
						if `gmax' == 0 {

							// Get maximum number of colors
							loc pcid `bkupmax'

						} // End IF Block to get maximum color ID

						// Else {
						else {

							// Set the pcid macro
							loc pcid `i'

						} // End ELSE Block for cases where the value is in the pcid list

						// Get the RGB values for the palette with the palette color id i
						qui: levelsof rgb if pcolor == `pcid' & colorid == `j'  ///
						& palette == `"`palnm'"', loc(xrgb)

						// Get the individual RGB value for this iteration
						loc col "`: word 1 of `xrgb''"

						// If color blind impairment simulation get the RGB values
						if `"`impaired'"' != "" {

							// Get simulated colors
							mata: translateColor(`: subinstr loc col `" "' `", "', all')

							// Sets the xaxis position for the baseline palette
							loc basex `= (`simcount' * 5) - 4'

							// Sets xaxis label for the baseline palette
							loc baselab `basex' "`i' "

							// Sets the xaxis position for the achromatopsia transformed palette
							loc achromx `= (`simcount' * 5) - 3'

							// Sets the xaxis label for the achromatopsia transformed palette
							loc achromlab `achromx' " a "

							// Sets the xaxis position for the protanopia transformed palette
							loc protanx `= (`simcount' * 5) - 2'

							// Sets the xaxis label for the protanopia transformed palette
							loc protanlab `protanx' " p "

							// Sets the xaxis position for the deuteranopia transformed palette
							loc deuterx `= (`simcount' * 5) - 1'

							// Sets the xaxis label for the deuteranopia transformed palette
							loc deuteranlab `deuterx' " d "

							// Sets the xaxis position for the tritanopia transformed palette
							loc tritanx `= (`simcount' * 5) - 0'

							// Sets the xaxis label for the tritanopia transformed palette
							loc tritanlab `tritanx' " t "

							// Build the command for graphing this individual color/label
							loc scat`i' `scat`i''							 ///
							(scatteri `j' `basex', mc("`col'") mlabc(black) ///
									/*msize(`sze' `sze')*/ mlc(black) ms(S))	 ///
							(scatteri `j' `achromx', mlc(black) ms(S)		 ///
								mc("`achromatopsia'") /*msize(`sze' `sze')*/)	 ///
							(scatteri `j' `protanx', ms(S) mlc(black)		 ///
								mc("`protanopia'") /*msize(`sze' `sze')*/)		 ///
							(scatteri `j' `deuterx', ms(S) mlc(black)		 ///
								mc("`deuteranopia'") /*msize(`sze' `sze')*/)	 ///
							(scatteri `j' `tritanx', ms(S) mlc(black) 		 ///
								mc("`tritanopia'") /*msize(`sze' `sze')*/)

							// Add to existing x-axis label macros
							loc xax `xax' `baselab' `achromlab' `protanlab' `deuteranlab' `tritanlab'

						} // End IF Block for impairment simulation

						// If not
						else {

							// Build the command for graphing this individual color/label
							loc scat`i' `scat`i'' (scatteri `j' `i', mc("`col'") ///
							mlabc(black) msize(`sze' `sze') mlc(black) ms(S))

						} // End ELSE Block for no color impairment simulation

					} // End Loop over colors within a given palette color id

					// Add these to a container macro used to build the full graph syntax
					loc cmd `cmd' `scat`i''

				} // End IF Block for acceptable max value

				// If it is outside the maximum number of colors
				else {

					// Don't alter command macro
					loc scat`i' `scat`i''

				} // For cases when the colors value is > max colors

				// Increment simvalue counter
				loc simcount = `simcount' + 1

			} // End Loop over the number of palette color ids to use

			// Check for simulation option
			if `"`impaired'"' != "" {

				// Adjust label angle and size
				loc xax `xax', angle(0)

				// Remove x-axis title to make room for the additional labeling
				loc xaxti ""

			} // End IF Block for impairment option

			// If option not selected
			else {

				// Sort the x axis values
				loc xax : list sort xax

				// Remove any duplicate values
				loc xax : list uniq xax

				loc xax `xax', angle(0)

				// Set the x-axis title
				loc xaxti "# Colors"

			} // End ELSE Block for graph w/o simulated colorblindness option

			// Get minimum value
			loc scales r(`= `mincol' - 0.25'(0.5)`= `maxcol' + 0.25')

			if `"`impaired'"' != "" {
				loc note1 "a = Achromatopsia    p = Protanopia"
				loc note2 "    d = Deuteranopia     t = Tritanopia"
				loc note note(`note1' `note2', size(medsmall) c(black) pos(7))
			}

			// Graph the color palette
			tw `cmd', ysca(r(1 `maxcol') off) xsca(`scales') xlab(`xax') 	 ///
			yti("") ylab(none, nogrid) legend(nodraw) `note'				 ///
			xti(`"`xaxti'"') graphr(margin(medlarge) fc(white) lc(white) 	 ///
			ic(white)) plotr(lc(white) fc(white) ic(white)) 				 ///
			name(`palnm'`color', replace) xsize(17) ysize(11) 				 ///
			ti("BrewScheme palette: `palnm' colors" `xtralab', 				 ///
			size(medsmall) span)

			// Store the name of the graph
			loc grnames `grnames' `palnm'`color'

		} // End Loop over palettes

		// Check combine option and make sure there are multiple palettes
		if "`combine'" != "" & `: word count `pal'' >= 2 {

			// If divisible by 5 and not 5
			if mod(`: word count `pal'', 5) == 0 & `: word count `pal'' / 5 != 1 {

				// Set rows as number of palettes divided by 5
				loc r rows(`: word count `pal''/5)

				// Use 5 columns for the images
				loc c cols(5)

			} // End IF Block for row/col options

			// Else if 4 palettes
			else if `: word count `pal'' / 4 == 1 {

				// Two rows
				loc r rows(2)

				// Two columns
				loc c cols(2)

			} // End ELSEIF Block for row/col options

			// Else if 6 palettes
			else if `: word count `pal''/6 == 1 {

				// Two rows of
				loc r rows(2)

				// Three columns
				loc c cols(3)

			} // End ELSEIF Block for row/col options

			// Else if # of palettes is divisible by 4
			else if mod(`: word count `pal'', 4) == 0 {

				// Number of rows = palettes / 4
				loc r rows(`: word count `pal''/4)

				// Use 4 columns
				loc c cols(4)

			} // End ELSEIF Block for row/col options

			// Else if number of palettes is divisible by 3
			else if mod(`: word count `pal'', 3) == 0 {

				// Number of Rows = palettes / 3
				loc r rows(`: word count `pal''/3)

				// Use three columns for the display
				loc c cols(3)

			} // End ELSEIF Block for row/col options

			// All other cases
			else {

				// Stata default number of rows
				loc r

				// Stata default number of columns
				loc c

			} // End ELSE Block for other cases

			// Combine graphs in a single graph image
			gr combine `grnames', altshrink graphr(ic(white) fc(white) 		 ///
			lc(white)) plotr(ic(white) fc(white) lc(white)) `r' `c' 		 ///
			ysize(8.5) xsize(11)

		} // End IF Block to combine the graphs

	// Return original state of the data to the user
	restore

// End the program
end