<?php

/*

 	Plugin Name: Googlyzer
	Plugin URI: http://oaktondata.com/googlyzer/
	Version: 2.2
	Author: Bill Edgar
	Author URI: http://oaktondata.com
	Text Domain: Googlyzer
	Description: Googlyzer adds an administrative dashboard to WordPress with microcharts for tracking website traffic data from Google Analytics, allowing WordPress administrators to easily view Google Analytics data for their website without leaving their WordPress Admin console.  Options allow administrative user to specify Google Analytics account, website profile, and desired date range for data display.
	Tags: Google Analytics, dashboard, web traffic, traffic, tracking, sparkline, microchart
	Package: Googlyzer
	License: BSD New (3-Clause License)
	
	Copyright (c) 2011-2012, Oakton Data LLC
	All rights reserved.

	Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
	    
	    * Redistributions of source code must retain the above copyright
	      notice, this list of conditions and the following disclaimer.
	    * Redistributions in binary form must reproduce the above copyright
	      notice, this list of conditions and the following disclaimer in the
	      documentation and/or other materials provided with the distribution.
	    * Neither the name of the Oakton Data LLC nor the
	      names of its contributors may be used to endorse or promote products
	      derived from this software without specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
	WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
	DISCLAIMED. IN NO EVENT SHALL Oakton Data LLC BE LIABLE FOR ANY
	DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
	ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
	
	This is the main PHP class file for the googlyzer plugin.
	
*/

// define constants
define( 'GOOGLYZER_VERSION', '2.2' );
define( 'BASE_URL', network_site_url() );

// directory locations
define( 'GOOGLYZER_PLUGIN_DIR', plugin_dir_url(__FILE__) );
define( 'GOOGLYZER_CSS', GOOGLYZER_PLUGIN_DIR . 'css/' );
define( 'GOOGLYZER_IMAGES', GOOGLYZER_PLUGIN_DIR . 'images/' );
define( 'GOOGLYZER_INCLUDES', dirname(__FILE__) . '/' . 'inc/' );
define( 'GOOGLYZER_JS', GOOGLYZER_PLUGIN_DIR . 'js/' );
define( 'GOOGLYZER_THEMES', GOOGLYZER_PLUGIN_DIR . 'themes/' );
define( 'GOOGLYZER_HTML', GOOGLYZER_PLUGIN_DIR . 'html/' );

// php class files
define( 'GOOGLYZER_ACCOUNTFEED_CLASS', 'AccountFeed' );
define( 'GOOGLYZER_ADMINPAGE_CLASS', 'AdminPage' );
define( 'GOOGLYZER_CHARTOBJ_CLASS', 'ChartObj' );
define( 'GOOGLYZER_CLIENTLOGIN_CLASS', 'ClientLogin' );
define( 'GOOGLYZER_DASHBOARD_CLASS', 'Dashboard' );
define( 'GOOGLYZER_DATAFEED_CLASS', 'DataFeed' );
define( 'GOOGLYZER_EXCEPTION_CLASS', 'Exception' );
define( 'GOOGLYZER_GOOGLEANALYTICSDATAOBJ_CLASS', 'GoogleAnalyticsDataObj' );
define( 'GOOGLYZER_GOOGLEAUTH_CLASS', 'GoogleAuth' );
define( 'GOOGLYZER_GOOGLEFEED_CLASS', 'GoogleFeed' );
define( 'GOOGLYZER_OPTIONS_CLASS', 'Options' );
define( 'GOOGLYZER_UNINSTALL', GOOGLYZER_PLUGIN_DIR . 'uninstall.php' );
define( 'GOOGLYZER_UTILITIES_CLASS', 'Utilities' );
define( 'GOOGLYZER_HOMEWIDGET_CLASS', 'HomeWidget' );

// definition and configuration files
define( 'GOOGLYZER_ADD_OPTIONS', GOOGLYZER_INCLUDES . 'options.cfg' );
define( 'GOOGLYZER_REGISTER_SCRIPTS', GOOGLYZER_INCLUDES . 'scripts.cfg' );
define( 'GOOGLYZER_REGISTER_STYLES', GOOGLYZER_INCLUDES . 'styles.cfg' );
define( 'GOOGLYZER_STYLE', 'style.css' );
define( 'GOOGLYZER_DASHBOARD_STYLE', 'dashboard.css' );

// html files
define( 'GOOGLYZER_ABOUT_HTML', GOOGLYZER_HTML . 'about.htm' );
define( 'GOOGLYZER_COMPOSITES_BEGIN_HTML', GOOGLYZER_HTML . 'composite_settings_begin.htm' );
define( 'GOOGLYZER_COMPOSITES_END_HTML', GOOGLYZER_HTML . 'composite_settings_end.htm' );
define( 'GOOGLYZER_DASHBOARD_HTML', GOOGLYZER_HTML . 'dashboard.htm' );
define( 'GOOGLYZER_GA_TRACKING_BEGIN_HTML', GOOGLYZER_HTML . 'ga_tracking_settings_begin.htm');
define( 'GOOGLYZER_GA_TRACKING_END_HTML', GOOGLYZER_HTML . 'ga_tracking_settings_end.htm');
define( 'GOOGLYZER_HOME_WIDGET_HTML', GOOGLYZER_HTML . 'home_widget.htm' );
define( 'GOOGLYZER_LINECHARTS_BEGIN_HTML', GOOGLYZER_HTML . 'linechart_settings_begin.htm' );
define( 'GOOGLYZER_LINECHARTS_INSTRUCTIONS_HTML', GOOGLYZER_HTML . 'linechart_settings_instructions.htm' );
define( 'GOOGLYZER_LINECHARTS_REPEAT_HTML', GOOGLYZER_HTML . 'linechart_settings_repeat.htm' );
define( 'GOOGLYZER_PIECHARTS_BEGIN_HTML', GOOGLYZER_HTML . 'piechart_settings_begin.htm' );
define( 'GOOGLYZER_PIECHARTS_INSTRUCTIONS_HTML', GOOGLYZER_HTML . 'piechart_settings_instructions.htm' );
define( 'GOOGLYZER_PIECHARTS_REPEAT_HTML', GOOGLYZER_HTML . 'piechart_settings_repeat.htm' );
define( 'GOOGLYZER_SETTINGS_HTML', GOOGLYZER_HTML . 'settings.htm' );
define( 'GOOGLYZER_SETTINGS_END_HTML', GOOGLYZER_HTML . 'settings_end.htm' );
define( 'GOOGLYZER_TABLES_BEGIN_HTML', GOOGLYZER_HTML . 'tables_settings_begin.htm' );
define( 'GOOGLYZER_TABLES_INSTRUCTIONS_HTML', GOOGLYZER_HTML . 'tables_settings_instructions.htm' );
define( 'GOOGLYZER_TABLES_REPEAT_HTML', GOOGLYZER_HTML . 'tables_settings_repeat.htm' );

// generic include method
function googlyzer__autoinclude( $class_name ) {
	try {
		include_once( GOOGLYZER_INCLUDES . $class_name . '.php' );
	} catch ( Exception $e ) {
		echo "<p>" . $e->getMessage() . "</p>";
	}
}

// generic getter method
function googlyzer__get($property,$obj) { // generic getter
	if (array_key_exists($property, get_class_vars(get_class($obj)))) {
		return $obj->$property;
	} else {
		die("<p>$property does not exist in " . get_class($obj) . "</p>");
	}
}

// generic setter method
function googlyzer__set($property,$value,$obj) { // generic setter
	if (array_key_exists($property, get_class_vars(get_class($obj)))) {
		$obj->$property = $value;
	} else {
		die("<p>$property does not exist in " . get_class($obj) . "</p>");
	}
}

// generic toString method
function googlyzer__toString($obj) { // generic object toString
	$attributes = get_class_vars(get_class($obj));
	$str = 'Class = ' . get_class($obj) . '\n';
	foreach ($attributes as $name => $value) {
		$str .= $name . ' = ' . $value . '\n';
	}
	return $str;
}

if ( !class_exists( 'googlyzer' ) ) {

	// googlyzer class
	class googlyzer {
		
		// public constructor method
		function googlyzer() { 
			$this->__construct();
		}
		
		// hidden constructor method
		function __construct() {
			
			googlyzer__autoinclude( GOOGLYZER_CHARTOBJ_CLASS );
			googlyzer__autoinclude( GOOGLYZER_EXCEPTION_CLASS );
			googlyzer__autoinclude( GOOGLYZER_GOOGLEFEED_CLASS ); // must be loaded first... base class
			googlyzer__autoinclude( GOOGLYZER_DATAFEED_CLASS );
			googlyzer__autoinclude( GOOGLYZER_GOOGLEANALYTICSDATAOBJ_CLASS );
			googlyzer__autoinclude( GOOGLYZER_CLIENTLOGIN_CLASS );
			googlyzer__autoinclude( GOOGLYZER_UTILITIES_CLASS );
			
			// add action hook for output of jquery.sparkline script
			add_action(
				$tag = 'wp_loaded',
				$callback = array( &$this, 'loadScripts' ),
				$priority = 10
				);
			// add action hook for GA tracking code in header
			add_action(
				$tag = 'wp_head',
				$callback = array( &$this, 'ga_tracking_header' ),
				$priority = 10
				);
			// add action hook for GA tracking code in footer
			add_action(
				$tag = 'wp_footer',
				$callback = array( &$this, 'ga_tracking_footer' ),
				$priority = 10
				);
			
			// verify we're on admin pages
			if ( is_admin() ) {

				// includes
				
				googlyzer__autoinclude( GOOGLYZER_ACCOUNTFEED_CLASS );
				googlyzer__autoinclude( GOOGLYZER_ADMINPAGE_CLASS );
				googlyzer__autoinclude( GOOGLYZER_DASHBOARD_CLASS );
				
				googlyzer__autoinclude( GOOGLYZER_GOOGLEAUTH_CLASS );
				googlyzer__autoinclude( GOOGLYZER_OPTIONS_CLASS );
				googlyzer__autoinclude( GOOGLYZER_HOMEWIDGET_CLASS );

				// runs when plugin is activated
				register_activation_hook( __FILE__, array( &$this, 'activate' ) );
				// runs when plugin is deactivated
				register_deactivation_hook( __FILE__, array( &$this, 'deactivate' ) );
				
				// instantiate googlyzer_options class
				if ( class_exists( 'googlyzer_options' ) ) {
					new googlyzer_options( $this );
				}
				
				// actions
				// add plugin setup function link on init
				add_action(
					$tag = 'init',
					$callback = array( &$this, 'setup' ),
					$priority = 1
					);
				
				// filters
				// add filter to output settings link with plugin list
				add_filter(
					$tag = 'plugin_action_links',
					$function_to_add = array( &$this, 'plugin_actions_links' ),
					$priority = 10,
					$accepted_args = 2
					);
				
			}
		
		}
		
		// activate method
		function activate() {
			// set up googlyzer
			$this->setup();
		}
		
		// deactivate method
		function deactivate() {
			// unregister googlyzer settings from wordpress database
			$settings = array( 'googlyzer-composites', 'googlyzer-linecharts', 'googlyzer-options', 'googlyzer-piecharts', 'googlyzer-tables' );
			foreach ( $settings as $key => $value ) {
				// unregister settings
				unregister_setting(
					$option_group = $value,
					$option_name = $value,
					$sanitize_callback = ''
					);
			}
		}
		
		// method to upgrade options
		function do_option_upgrade( $version, $option_group, $options ) {
			// case for upgrading 1.0 options
			if ( $version == '1.0' ) {
				// record GA table ID from old website option
				$options['standard']['ga_tableid'] = $options['website'];
				unset( $options['website'] );
				// set up array of old option names
				$option_names = array( 'date_range', 'start', 'end' );
				// record old option values and remove old keys
				foreach ( $option_names as $name ) {					
					$options['standard'][$name] = $options[$name];
					unset( $options[$name] );
				}
			// case for upgrading 1.1 options
			} else if ( $version == '1.1' ) {
				switch ( $option_group ) {
					// general options case handled as version 1.0 upgrade
					case 'googlyzer-linecharts':
						// set up array of old option key prefixes
						$key_maps = array( 
							'linechart1' =>	'pageviews',
							'linechart2' =>	'visitors',
							'linechart3' => 'newVisits',
							'linechart4' => 'visitBounceRate' 
							);
						// first record old option values in new locations
						foreach ( $key_maps as $new_key => $old_key ) {
							if ( array_key_exists( $old_key . '_enable', $options ) && $options[$old_key . '_enable'] !== '' ) {
								$options[$new_key]['enable'] = $options[$old_key . '_enable'];
							} else {
								$options[$new_key]['enable'] = 'disabled';
							}
							if ( array_key_exists( $old_key . '_metadata', $options ) && $options[$old_key . '_metadata'] !== '' ) {
								$options[$new_key]['metadata_enable'] = $options[$old_key . '_metadata'];
							} else {
								$options[$new_key]['metadata_enable'] = 'disabled';
							}
							if ( array_key_exists( $old_key . '_history', $options ) && $options[$old_key . '_history'] !== '' ) {
								$options[$new_key]['history_enable'] = $options[$old_key . '_history'];
							} else {
								$options[$new_key]['history_enable'] = 'disabled';
							}
							// record color
							$options[$new_key]['color'] = $options[$old_key . '_color'];
						}
						// then remove array keys for old options
						foreach ( $key_maps as $new_key => $old_key ) {
							unset( $options[$old_key . '_enable'] );
							unset( $options[$old_key . '_color'] );
							unset( $options[$old_key . '_metadata'] );
							unset( $options[$old_key . '_history'] );
						}
						break;
					case 'googlyzer-piecharts':
						// set up array of old option key prefixes
						$key_maps = array(
							'piechart1' => 'browser',
							'piechart2' => 'source'
							);
						// record old option values in new locations and remove array keys for old options
						foreach ( $key_maps as $new_key => $old_key ) {
							for ( $x=1; $x<6; $x++ ) {
								$options[$new_key]['slice_color_' . $x] = $options[$old_key . '_color_' . $x];
								unset( $options[$old_key . '_color_' . $x] );
							}
							$options[$new_key]['max_results'] = $options[$old_key . '_number'];
							unset( $options[$old_key . '_number'] );
						}
						break;
					case 'googlyzer-tables':
						// set up array of old option key prefixes
						$key_maps = array(
							'table1' => 'pageTitle',
							'table2' => 'keyword'
							);
						// record old option values in new locations and remove array keys for old options
						foreach ( $key_maps as $new_key => $old_key ) {
							$options[$new_key]['num_rows'] = (int) $options[$old_key . '_number'];
							unset( $options[$old_key . '_number'] );
						}
						break;
				}
			// case for upgrading 1.2 options
			} else if ( $version == '1.2' ) {
				// add new general option fields to options array with defaults
				$options['standard']['dash_enable'] = 'enabled';
				$options['standard']['ga_auth_token'] = null;
				$options['standard']['ga_login'] = null;
				$options['standard']['ga_password'] = null;
			} else if ( $version == '2.0' ) {
				// no option upgrade necessary, only added googlyzer-ga_tracking
			}
			return $options;
		} // end method do_option_upgrade
		
		function ga_tracking_header() {
			// retrieve ga_tracking options array from wordpress database
			$options = get_option(
				$show = 'googlyzer-ga_tracking',
				$default = false
				);
			// if ga_tracking options array was successfully retrieved
			if ( $options !== false ) {
				$web_property_id = ( array_key_exists( 'ga_webpropertyid', $options['ga_tracking_general'] ) ) ? $options['ga_tracking_general']['ga_webpropertyid'] : '';
				$enable = ( array_key_exists( 'enable', $options['ga_tracking_general'] ) ) ? $options['ga_tracking_general']['enable'] : 'disabled';
				$placement = ( array_key_exists( 'placement', $options['ga_tracking_general'] ) ) ? $options['ga_tracking_general']['placement'] : 'manual';
				$track_admin = ( array_key_exists( 'track_admin', $options['ga_tracking_general'] ) ) ? $options['ga_tracking_general']['track_admin'] : 'manual';
				if ( $enable === 'enabled' ) {
					if ( current_user_can( 'administrator' ) && $track_admin === 'enabled' || !current_user_can( 'administrator' ) ) {
						if ( $placement === 'header' && !empty( $web_property_id ) ) {
							$this->ga_tracking_script( $web_property_id );
						}
					}
				}
			}
		}
		
		function ga_tracking_footer() {
			// retrieve ga_tracking options array from wordpress database
			$options = get_option(
					$show = 'googlyzer-ga_tracking',
					$default = false
			);
			// if ga_tracking options array was successfully retrieved
			if ( $options !== false ) {
				$web_property_id = ( array_key_exists( 'ga_webpropertyid', $options['ga_tracking_general'] ) ) ? $options['ga_tracking_general']['ga_webpropertyid'] : '';
				$enable = ( array_key_exists( 'enable', $options['ga_tracking_general'] ) ) ? $options['ga_tracking_general']['enable'] : 'disabled';
				$placement = ( array_key_exists( 'placement', $options['ga_tracking_general'] ) ) ? $options['ga_tracking_general']['placement'] : 'manual';
				$track_admin = ( array_key_exists( 'track_admin', $options['ga_tracking_general'] ) ) ? $options['ga_tracking_general']['track_admin'] : 'manual';
				if ( $enable === 'enabled' ) {
					if ( current_user_can( 'administrator' ) && $track_admin === 'enabled' || !current_user_can( 'administrator' ) ) {
						if ( $placement === 'footer' && !empty( $web_property_id ) ) {
							$this->ga_tracking_script( $web_property_id );
						}
					}
				}
			}
		}
		
		function ga_tracking_script( $web_property_id ) {
			?>
				<!-- Google Analytics tracking code inserted by Googlyzer -->
				<script type="text/javascript">
					var _gaq = _gaq || [];
					_gaq.push(['_setAccount', '<?php echo $web_property_id; ?>']);
					_gaq.push(['_trackPageview']);
				
					(function() {
				    	var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
				    	ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
				    	var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
				  		})();
		  		</script>
				<!-- Google Analytics tracking code inserted by Googlyzer -->
			<?php 
		}
		
		function loadScripts() {
			// register script with wordpress
			wp_register_script(
				$handle = 'jquery.sparkline',
				$src = GOOGLYZER_JS . 'jquery.sparkline.js',
				$deps = array( 'jquery' ),
				$ver = GOOGLYZER_VERSION,
				$in_footer = false
				);
			// print script
			wp_enqueue_script( $handle = 'jquery.sparkline' );
		} // end method loadSparklineScript
		
		/*
		 * @TODO: update upgrade options function for version 2.1
		 */
		
		// method to check options to upgrade plugin options, if necessary
		function upgrade_options() {
			$options_groups = array ( 'googlyzer-composites', 'googlyzer-options', 'googlyzer-linecharts', 'googlyzer-piecharts', 'googlyzer-tables' );
			foreach ( $options_groups as $key => $group ) {
				// retrieve options array from wordpress database
				$options = get_option(
					$show = $group,
					$default = false
					);
				// check to see if option array exists
				if ( $options !== false ) {
					if ( array_key_exists( 'website', $options ) && $group === 'googlyzer-options' ) {
						// general options group match
						if ( array_key_exists( 'dash_enable', $options ) ) {
							// version 2.0 general options match, execute upgrade
							$options = $this->do_option_upgrade( '2.0', 'googlyzer-options', $options );
						} elseif ( array_key_exists( 'ga_tableid', $options ) ) {
							// version 1.2 general options match, execute upgrade
							$options = $this->do_option_upgrade( '1.2', 'googlyzer-options', $options );
						} else {
							// version 1.1 or 1.0 general options match, execute upgrade				
							$options = $this->do_option_upgrade( '1.0', 'googlyzer-options', $options );
						}
					} else if ( array_key_exists( 'pageviews_enable', $options ) && $group === 'googlyzer-linecharts' ) {
						// version 1.1 linechart options match, execute upgrade
						$options = $this->do_option_upgrade( '1.1', 'googlyzer-linecharts', $options );
					} else if ( array_key_exists( 'browser_color_1', $options ) && $group === 'googlyzer-piecharts' ) {
						// version 1.1 piechart options match, execute upgrade
						$options = $this->do_option_upgrade( '1.1', 'googlyzer-piecharts', $options );
					} else if ( array_key_exists( 'pageTitle_number', $options ) && $group === 'googlyzer-tables' ) {
						// version 1.1 table options match, execute upgrade
						$options = $this->do_option_upgrade( '1.1', 'googlyzer-tables', $options );
					}
					// update new options in wordpress database
					update_option(
						$option_name = $group, 
						$newvalue = $options
						);
				}
			}
		} // end method upgrade_options
		
		// method to output plugin action links on main plugins page
		function plugin_actions_links( $links, $file ) {
			static $this_plugin;
 			// set $this_plugin to current file name
		    if ( empty( $this_plugin ) ) {
		        $this_plugin = plugin_basename( __FILE__ );
		    }
		 
		    // check to make sure we are on the correct plugin
		    if ( $file == $this_plugin ) {
		        // the anchor tag and href to the URL. For a "Settings" link, this needs to be the url of your settings page
		        $settings_link = '<a href="' . 
		        	get_bloginfo( 'wpurl' ) . 
		        	'/wp-admin/options-general.php?page=googlyzer">Settings</a>';
		        // add the link to the list
		        array_unshift( $links, $settings_link );
		    }
		 	// return modified array of links
		    return $links;
		}
		
		// setup method
		function setup() {
			// upgrade options if necessary
			$this->upgrade_options();
		}
		
		// uninstall method
		function uninstall() {
			if ( !defined( 'ABSPATH' ) || !defined( 'WP_UNINSTALL_PLUGIN' ) ) {
				exit();
			}
			// remove googlyzer settings from wordpress database
			$settings = array( 'googlyzer-composites', 'googlyzer-ga_tracking', 'googlyzer-linecharts', 'googlyzer-options', 'googlyzer-piecharts', 'googlyzer-tables' );
			foreach ( $settings as $key => $value ) {
				// remove options from WordPress database
				delete_option( $value );
			}
		}
		
		// validate method
		function validate( $rawinput ) {
			return $rawinput;
		}
		
	}
	
} // end class googlyzer

// instantiate new googlyzer object
if ( class_exists( 'googlyzer' ) ) {
	new googlyzer();
}
?>