<?php
/*
Plugin Name: Woocommerce Table Rate Shipping Pro
Plugin URI: http://jem-products.com/woocommerce-table-rate-shipping-pro/
Description: Table Rate Shipping for Woocommerce - Pro Version 
Version: 1.3.1
Author: JEM Plugins
Author URI: http://www.jem-products.com
*/
 
 
 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
 //lets define some constants
 define('JEM_DOMAIN', 'jem-table-rate-pro-shipping-for-woocommerce');
 define( 'JEM_URL', plugin_dir_url( __FILE__ ) );  // Plugin URL
/**
 * Check if WooCommerce is active
 */
 
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
 
	function jem_table_rate_init() {
		if ( ! class_exists( 'JEM_Table_Rate_Shipping_Method_Pro' ) ) {
			class JEM_Table_Rate_Shipping_Method_Pro extends WC_Shipping_Method {
				/**
				 * Constructor for your shipping class
				 *
				 * @access public
				 * @return void
				 */
				public function __construct() {
					$this->id                 = 'jem_table_rate_pro'; 					// Id for your shipping method. Should be uunique.
					$this->method_title       = __( 'Table Rate Pro', JEM_DOMAIN ); 	// Title shown in admin
					$this->method_description =__( 'Table Rate lets you define shipping based on a table of values', JEM_DOMAIN ); // Description shown in admin
 
 					$this->zones_settings 	  = $this->id.'zones_settings';
 					$this->rates_settings 	  = $this->id.'rates_settings';
					$this->enabled            = "yes"; 								// This can be added as an setting but for this example its forced enabled
					$this->title              = "Table Rate Shipping - Pro"; 				// This can be added as an setting but for this example its forced.
 
 					$this->option_key  		  = $this->id.'_table_rates';			//The key for wordpress options
					$this->options			  = array();									//the actual tabel rate options saved 
 					$this->condition_array	= array();									//holds an array of CONDITIONS for the select
					$this->country_array	= array();									//holds an array of COUNTRIES for the select
					$this->states_array		= array();									//holds ALL the states for ALL countries - no ajax way to get them!!!
					$this->zone_type_array	= array();									//holds an array of ZONE TYPES for the select
					$this->shipping_class_array	= array();								//holds an array of SHIPPING CLASSES for the select
					$this->counter			= 0;									//we use this to keep unique names for the rows
					$this->init();
					
					$this->get_options();											//load the options
				}
 

				
				
				/**
				 * Init your settings
				 *
				 * @access public
				 * @return void
				 */
				function init() {
					// Load the settings API
					$this->init_form_fields(); 	// This is part of the settings API. Override the method to add your own settings
					$this->init_settings(); 	// This is part of the settings API. Loads settings you previously init.
 					
					$this->title = $this->settings['title'];
					
 					//set up the select arrays
					$this->create_select_arrays();
					
					// Save settings in admin if you have any defined
					add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
					//And save our options
					add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_custom_settings' ) );
					
				}
				
				/**
				** This initialises the form field
				*/
				function init_form_fields(){
					
					$this->form_fields = array(
	                    'enabled' => array(
                            'title' 		=> __( 'Enable/Disable', JEM_DOMAIN ),
                            'type' 			=> 'checkbox',
                            'label' 		=> __( 'Enable this shipping method', JEM_DOMAIN ),
                            'default' 		=> 'no'
						),
	                    'title' => array(
                            'title' 		=> __( 'Checkout Title', JEM_DOMAIN ),
                            'description' 		=> __( 'This controls the title which the user sees during checkout.', JEM_DOMAIN ),
                            'type' 			=> 'text',
                            'default' 		=> 'Table Rate Shipping',
                            'desc_tip'     => true
						),
	                    'handling_fee' => array(
                            'title' 		=> __( 'Handling Fee', JEM_DOMAIN ),
                            'description' 		=> __( 'Enter an amount for the handling fee - leave BLANK to disable.', JEM_DOMAIN ),
                            'type' 			=> 'text',
                            'default' 		=> ''
						),
						'tax_status' => array(
							'title' 		=> __( 'Tax Status', JEM_DOMAIN ),
							'type' 			=> 'select',
							'default' 		=> 'taxable',
							'options'		=> array(
								'taxable' 	=> __( 'Taxable', JEM_DOMAIN ),
								'notax' 		=> __( 'Not Taxable', JEM_DOMAIN ),
							)
						),
						'table_rates_table' => array(
							'type'				=> 'table_rates_table'           	// these get called automagically by woo
						),							
						'shipping_class_table' => array(
							'type'				=> 'shipping_class_table'     		// these get called automagically by woo
						),							
					);
				
				}
				

				/**
				* admin_options
				* These generates the HTML for all the options
				*/
				function admin_options() {
				?>
		
					<h2><?php _e('Table Rate Shipping Options','woocommerce'); ?></h2>
					 <table class="form-table">
					 <?php $this->generate_settings_html(); ?>
					 </table> 
					 <h3>
				<?php					
				}
				
				
				/**
				 * Returns the latest counter 
				*/
				function get_counter(){
					$this->counter = $this->counter + 1;
					return $this->counter;	
				}
				
				
				/**
				 * Generates HTML for table_rate settings table.
				 * this gets called automagically!
				 */
				function generate_table_rates_table_html() {
					ob_start();
					
					
					//OK lets pump out some rows to see how it goes!!!
					// we put the jscript stuff at the top
					?>
					<tr>
						<th scope="row" class="titledesc"><?php _e( 'Table Rates', JEM_DOMAIN ); ?></th>
						<td id="<?php echo $this->id; ?>_settings">
							<table class="shippingrows widefat">
						        <col style="width:0%">
						        <col style="width:0%">
						        <col style="width:0%">
						        <col style="width:100%;">
								<thead>
									<tr>
										<th class="check-column"></th>
										<th><?php _e( 'Shipping Zone Name', JEM_DOMAIN ); ?> </th>
										<th><?php _e( 'Zone Type', JEM_DOMAIN ); ?> </th>
										<th><?php _e( 'Values', JEM_DOMAIN ); ?> </th>
									</tr>
								</thead>
								<tbody style="border: 1px solid black;">
									<tr class="jem-default-zone" id="jem-default-zone">
										<td></td>
										<td><?php _e( 'Default Zone (Everything Else)', JEM_DOMAIN ); ?></td>
										<td><?php _e( 'All', JEM_DOMAIN ); ?>
										</td>
										<td>
											<?php _e( 'All Other Countries', JEM_DOMAIN ); ?>
										</td>
									</tr>
									<tr class="jem-default-rates" id="jem-default-rates">
									</tr>

									
									
									<tr class="jem-rate-holder">
										<td colspan="1">
										</td>
										<td colspan="3">
											<table class="jem-rate-table shippingrows widefat" id="default_rates">
												<thead>
													<tr>
														<th></th>
														<th style="width: 20%"><?php _e( 'Shipping Type', JEM_DOMAIN ); ?> <a class="tips" data-tip="<?php _e( 'Select the Shipping Type this rule is for.', JEM_DOMAIN ); ?>">[?]</a></th>
														<th style="width: 20%"><?php _e( 'Class', JEM_DOMAIN ); ?>  <a class="tips" data-tip="<?php _e( 'Select the Shipping Class this rule is for.', JEM_DOMAIN ); ?>">[?]</a></th>
														<th style="width: 20%"><?php _e( 'Condition', JEM_DOMAIN ); ?>   <a class="tips" data-tip="<?php _e( 'Select the Condition this rule is for.', JEM_DOMAIN ); ?>">[?]</a></th>
														<th style="width: 8%"><?php _e( 'Min Value', JEM_DOMAIN ); ?>  <a class="tips" data-tip="<?php _e( 'Enter the minimum value for this rule.', JEM_DOMAIN ); ?>">[?]</a></th>
														<th style="width: 8%"><?php _e( 'Max Value', JEM_DOMAIN ); ?>  <a class="tips" data-tip="<?php _e( 'Enter the maximum value for this rule, use * for no upper limit.', JEM_DOMAIN ); ?>">[?]</a></th>
														<th style="width: 8%"><?php _e( 'Base Amt', JEM_DOMAIN ); ?>  <a class="tips" data-tip="<?php _e( 'Enter the shipping amount for this rule.', JEM_DOMAIN ); ?>">[?]</a></th>
														<th style="width: 8%"><?php _e( 'Per Item', JEM_DOMAIN ); ?>  <a class="tips" data-tip="<?php _e( 'Enter the shipping amount for this rule.', JEM_DOMAIN ); ?>">[?]</a></th>
														<th style="width: 8%"><?php _e( 'Per', JEM_DOMAIN ); ?>  <?php echo get_option('woocommerce_weight_unit'); ?> <a class="tips" data-tip="<?php _e( 'Enter the shipping amount for this rule.', JEM_DOMAIN ); ?>">[?]</a></th>
														</tr>
												</thead>
												<tr>
													<td colspan="9" class="add-rate-buttons">
														<a href="#" class="add button" name="xxx-default-rate"><?php _e( 'Add New Rate', JEM_DOMAIN ); ?></a>
														<a href="#" class="delete button"><?php _e( 'Delete Selected Rates', JEM_DOMAIN ); ?></a>
													</td>
												</tr>
											</table>
										</td>
									</tr>									
									
									
									<tr style="border: 1px solid black;">
										<td colspan="5" class="add-zone-buttons">
											<a href="#" class="add button"><?php _e('Add New Shipping Zone', JEM_DOMAIN) ?></a>
											<a href="#" class="delete button"><?php _e('Delete Selected Zones', JEM_DOMAIN) ?></a>
										</td>
									</tr>									
									
									
									
								</tbody>
							</table>
						</td>
					</tr>
					<script>
				   		var options = <?php echo json_encode($this->create_dropdown_options()); ?>;

						var country_array = <?php echo json_encode($this->country_array); ?>;
						var condition_array = <?php echo json_encode($this->condition_array); ?>;
						var states_array = <?php echo json_encode($this->states_array); ?>;
						var zone_type_array = <?php echo json_encode($this->zone_type_array); ?>;
						var shipping_class_array = <?php echo json_encode($this->shipping_class_array); ?>;
						var shipping_types = <?php echo json_encode($this->options['shipping-types']); ?>;
						var pluginID = <?php echo json_encode($this->id); ?>;

						var lastID = 0;

						var weight_unit = "<?php echo get_option('woocommerce_weight_unit'); ?>";
						

						
						//lets attach the  handler when they change the Zone TYPE
						jQuery(".zone-type-select").live("change", function(){
							zone_type_changed(this);
						});

						//lets attach the  handler when they change country select
						jQuery(".zone-country-select").live("change", function(){
							zone_country_changed(this);
						});

												
							<?php
									//create the default zone rate rows if they exist
									if(isset($this->options['default-rates'])){
										
										//loop thru the default rates
										foreach ($this->options['default-rates']['min'] as $key => $value){
											$row = array();
											$row['rates'][0]['min'] = $this->options['default-rates']['min'][$key];
											$row['rates'][0]['max'] = $this->options['default-rates']['max'][$key];
											$row['rates'][0]['shipping'] = $this->options['default-rates']['shipping'][$key];
											$row['rates'][0]['shippingType'] = $this->options['default-rates']['rate-type-select'][$key];
											$row['rates'][0]['shippingClass'] = $this->options['default-rates']['rate-class-select'][$key];
											$row['rates'][0]['shippingCondition'] = $this->options['default-rates']['rate-condition-select'][$key];
											$row['rates'][0]['perItem'] = $this->options['default-rates']['perItem'][$key];
											$row['rates'][0]['perWeight'] = $this->options['default-rates']['perWeight'][$key];
												
											//TODO need to add the rest of the keys here
											
											//and then pump out the jquery
											$row = json_encode($row);
											
											//it goes in the default_rates table before the las row (which is the buttons)
											echo "jQuery('#default_rates tbody tr:last').before(create_rate_row('default-rate', {$row}) );\n";
										}
										//echo "jQuery('#default_rates tbody').html(create_zone_row('default-rate'), null);";
									}		
							
									//account for no rates to beigin with!
									if(array_key_exists('rates', $this->options)) {
										
										//populate the default rates
										
										
										//Ok now lets build the table for all our zones & data - lots of jQuery!!!!
										foreach($this->options['rates'] as $key => $value){
										
											//skip the default ones
											if($key =="default-rate") continue;
											
											
											//add the key back into the json object - we make an array of keys, easier to process later
											$value['key'] = $key;
											$row = json_encode($value);
											//echo "jQuery('#{$this->id}_settings table tbody tr:last').before(create_zone_row({$row}));\n";
											//echo "jQuery('#{$this->id}_settings table tbody tr:nth-last-child(4)').before(create_zone_row({$row}));\n";
											echo "jQuery('#jem-default-zone').before(create_zone_row({$row}));\n";
												
											//OK now the row is created we need to select the corect Zone Type and propegate the chnage event....
											
											//first lets get the Zone type
											$type = $value['zone_type'];
											
											
											//now lets get the TR we just inserted - it will be BEFORE the default zone
											//Last row is add/delete buttons
											//-1 & -2 is the default zone & rates 
											//-3  row is are the rates
											//-4 row is the zone info
											//echo "var thisRow = jQuery('#{$this->id}_settings table tbody tr:nth-last-child(5) .zone-type-select');";
											echo "var thisRow = jQuery('#jem-default-zone').prev().prev().find('.zone-type-select');\n";
											echo "thisRow.val('{$type}');\n";
											//the event doesn't get called so lets fake it!
											echo "zone_type_changed(jQuery(thisRow));\n";
											
											//now lets set the values on the country and values in the zone area
											//if we have a state or zip set the country
											if($type == 'state' || $type=='zip'){
												$country = $value['zone_country'];
												//echo "thisRow = jQuery('#{$this->id}_settings table tbody tr:nth-last-child(5) .zone-country-select');";
												echo "var thisRow = jQuery('#jem-default-zone').prev().prev().find('.zone-country-select');\n";
												echo "thisRow.val('{$country}');\n";
												
												//now trigger country changed
												echo "zone_country_changed(thisRow);\n";
											}
											
											//lets populate the values
											if($type == "state" || $type == "country"){
												$vals = json_encode($value['zone_values']);
												
												echo "jQuery('#jem-default-zone').prev().prev().find('.zone-values').val({$vals});\n";
												echo "jQuery('select.zone-values').select2();\n";
												//
											} elseif ($type == 'zip'){
												$vals = json_encode($value['zone_values']);
												//echo "jQuery('#{$this->id}_settings table tbody tr:nth-last-child(5) .zone-values').val({$vals});";
												echo "jQuery('#jem-default-zone').prev().prev().find('.zone-values').val({$vals});\n";
											}
											
											
										}
										
									}
									

						   	?>
							   
						
						//Handles when a zone type is changed
						// Takes input a jquery object of the select
						function zone_type_changed(sel){
							console.log('zt changed');
							console.log(sel);

							console.log( jQuery(sel).find('option:selected').val() );

							//get the next TD
							sib = jQuery(sel).parent().next();

							//inside the td is a DIV = this div's name is the key for this zone! - lets get it!
							var id = sib.find('div').attr('name');
							console.log(sib);
							console.log(id);
							console.log('simon');
							console.log(jQuery(sel).find('option:selected').val());
							//If country - lets hide the sub-selector  
							switch(jQuery(sel).find('option:selected').val()) {
							case "country":
								//The select box needs to be hidden
								//The value box needs to be a select of countries
								//show the value box
								sib.find('.zone-country-select').addClass('hidden');

								//replace the values div with a country select

								var html = '<select multiple class="zone-values" name="zone-values[' + id + '][]" >' + generate_country_html([]) + '</select>';
								sib.find('.zone-value-div').html(html);

								if (jQuery().chosen) {


									jQuery("select.zone-values").chosen({
										width: '350px',
										disable_search_threshold: 5
									});
									
								} else {
									jQuery("select.zone-values").select2();
								}
								

								break;

							case "state":
								//The select box needs to be countries
								//The value box needs to be a select of states
								sib.find('.zone-country-select').removeClass('hidden');
								
								//replace the values div with an empty select - will get populated when they pick a country
								var html = '<br><select multiple class="zone-values" name="zone-values[' + id + '][]"></select>';
								sib.find('.zone-value-div').html(html);


								if (jQuery().chosen) {


									jQuery("select.zone-values").chosen({
										width: '350px',
										disable_search_threshold: 5
									});
									
								} else {
									jQuery("select.zone-values").select2();
								}

								//now we need to trigger the load of the correct states if a country is selected
								var nextSel = jQuery(sel).parent().next().find('.zone-country-select');
								zone_country_changed(nextSel);
								
								break;

							case "zip" :
								//The select box needs to be a list of countries
								//The value box needs to be a text input box
								sib.find('.zone-country-select').removeClass('hidden');

								var html = '<br><textarea rows="5" cols="50" class="zone-values" name="zone-values[' +id + ']"></textarea>';
								sib.find('.zone-value-div').html(html);
								
								break;
							}


							
						}

						//Handles when a zone COUNTRY is changed
						// Takes input a jquery object of the select
						function zone_country_changed(sel){
							console.log('zone country changed');
							console.log(sel);

							//get the ID of this row
							var id = jQuery(sel).closest('tr').attr('id');

							console.log('id:' + id);
							
							console.log( jQuery(sel).find('option:selected').val() );

							
							//first lets get the zone type select - up to td prev td, then the selected
							var zt = jQuery(sel).parent().prev().find('option:selected').val();
							console.log('it was: ' + zt);


							//Ok now switch based on the zone type
							switch(zt){
								case 'state':
									//load the states for this country into the select box
									var states = states_array[jQuery(sel).find('option:selected').val()];
									console.log(states);
		
									//it will eithe be false or an empty array - both get nothing
									var html = "";
									if(states == false || states.length ==0){
										console.log('nothing');
										html = '<br><select class="zone-values"></select>';
									} else {
										console.log('got soemthing');
										html = '<br><select multiple class="zone-values" name="zone-values[' + id + '][]">';
										
										//loop around the states
										for(var key in states){
											html += '<option value="' + key + '">' + states[key] + '</option>';
										}
		
										html += '</select>';
										
										
									}
		
		
		
									//now get the div sibling of the country select box
									div = jQuery(sel).next();
									console.log(div);
									div.html(html);
		
									//turn on select2 etc
									if (jQuery().chosen) {
		
		
										jQuery("select.zone-values").chosen({
											width: '350px',
											disable_search_threshold: 5
										});
										
									} else {
										jQuery("select.zone-values").select2();
									}
								
									break;

								case 'zip':

									//lets create the text area
									var html = '<br><textarea rows="5" cols="50" class="zone-values" name="zone-values[' +id + ']"></textarea>';
									div = jQuery(sel).next();
									div.html(html);
									break;
							}


						}

					
						/**
						* This creates a new ZONE row
						*/
						function create_zone_row(row){
							//lets get the ID of the last one
							
							var el = '#' + pluginID + '_settings .jem-zone-row';
							lastID = jQuery(el).last().attr('id');
							
							//Handle no rows
							if(typeof lastID == 'undefined' || lastID == ""){
								lastID =1;
							} else {
								lastID = Number(lastID) + 1;
							}
							
							var html = '\
									<tr id="' + lastID + '" class="jem-zone-row" >\
										<input type="hidden" value="' + lastID + '" name="key[' + lastID + ']"></input>\
										<td><input type="checkbox" class="jem-zone-checkbox"></input></span></td>\
										<td><input type="text" size="30" value="' + row["key"] +'"  name="zone-name[' + lastID + ']"/></td>\
										<td>\
											<select name="zone-type[' + lastID + ']" class="zone-type-select">\
											' + generate_zone_type_html(row.zoneType) +'\
											</select>\
										</td>\
										<td>\
										<select name="zone-country[' + lastID + ']" class="zone-country-select">\
										' + generate_country_html(row.zone_country) +'\
										</select>\
										<div class="zone-value-div" name="' + lastID + '">\
										<br class="zone-country-select">\
										<select class="zone-values"> testing</select>\
										</div>\
										</td>\
									</tr>\
							';
							
							//This is the row for that holds the rates
							html += '\
								<tr class="jem-rate-holder">\
									<td colspan="1">\
									</td>\
									<td colspan="3">\
										<table class="jem-rate-table shippingrows widefat" id="' + lastID + '_rates">\
											<thead>\
												<tr>\
													<th></th>\
													<th style="width: 20%"><?php _e( 'Shipping Type', JEM_DOMAIN ); ?> <a class="tips" data-tip="<?php _e( 'Select the Shipping Type this rule is for.', JEM_DOMAIN ); ?>">[?]</a></th>\
													<th style="width: 20%"><?php _e( 'Class', JEM_DOMAIN ); ?>  <a class="tips" data-tip="<?php _e( 'Select the Shipping Class this rule is for.', JEM_DOMAIN ); ?>">[?]</a></th>\
													<th style="width: 20%"><?php _e( 'Condition', JEM_DOMAIN ); ?>   <a class="tips" data-tip="<?php _e( 'Select the Condition this rule is for.', JEM_DOMAIN ); ?>">[?]</a></th>\
													<th style="width: 8%"><?php _e( 'Min Value', JEM_DOMAIN ); ?>  <a class="tips" data-tip="<?php _e( 'Enter the minimum value for this rule.', JEM_DOMAIN ); ?>">[?]</a></th>\
													<th style="width: 8%"><?php _e( 'Max Value', JEM_DOMAIN ); ?>  <a class="tips" data-tip="<?php _e( 'Enter the maximum value for this rule, use * for no upper limit.', JEM_DOMAIN ); ?>">[?]</a></th>\
													<th style="width: 8%"><?php _e( 'Base Amt', JEM_DOMAIN ); ?>   <a class="tips" data-tip="<?php _e( 'Enter the base shipping amount for this rule.', JEM_DOMAIN ); ?>">[?]</a></th>\
													<th style="width: 8%"><?php _e( 'Per Item', JEM_DOMAIN ); ?>   <a class="tips" data-tip="<?php _e( 'Each item in the cart will get this charge.', JEM_DOMAIN ); ?>">[?]</a></th>\
													<th style="width: 8%"><?php _e( 'Per', JEM_DOMAIN ); ?>  ' + weight_unit + '  <a class="tips" data-tip="<?php _e( 'This will be applied to the weight', JEM_DOMAIN ); ?>">[?]</a></th>\
													</tr>\
											</thead>\
											' + create_rate_row(lastID, row) +'\
											<tr>\
												<td colspan="9" class="add-rate-buttons">\
													<a href="#" class="add button" name="key_' + lastID + '"><?php _e( 'Add New Rate', JEM_DOMAIN ); ?> </a>\
													<a href="#" class="delete button"><?php _e( 'Delete Selected rates', JEM_DOMAIN ); ?> </a>\
												</td>\
											</tr>\
										</table>\
									</td>\
								</tr>\
							';
							
							return html;
						}

						/**
						* This creates a new RATE row
						* The id of this zone is passed in, along with optional data
						*/
						function create_rate_row(lastID, row){
							
							//if we are adding the defualt rate row then we will need different nmaes for the items
							
							if(lastID=="default-rate"){
								type = 'default-rate-type-select[]';
								cls = 'default-rate-class-select[]';
								condition = 'default-rate-condition-select[]';
								min = 'default-min[]';
								max = 'default-max[]';
								shipping = 'default-shipping[]';
								perItem = 'default-per-item[]';
								perWeight = 'default-per-weight[]';
							} else {
								type = 'rate-type-select[' + lastID + '][]';
								cls = 'rate-class-select[' + lastID + '][]';
								condition = 'rate-condition-select[' + lastID + '][]';
								min = 'min[' + lastID + '][]';
								max = 'max[' + lastID + '][]';
								shipping = 'shipping[' + lastID + '][]';
								perItem = 'per-item[' + lastID + '][]';
								perWeight = 'per-weight[' + lastID + '][]';
				}
							
							if(row == null || row.rates.length == 0){
								//lets manufacture a rows
								//create dummy row
								var row = {};
								row.key = "";
								row.condition = [""];
								row.countries = [];
								row.rates = [];
								row.rates.push([]);
								row.rates[0].min = "0";
								row.rates[0].max = "0";
								//row.rates[0].shipping = "";
								row.rates[0].shippingType = "";
								row.rates[0].shippingClass = "";
								row.rates[0].shippingCondition = "";
								row.rates[0].perItem = "0";
								row.rates[0].perWeight = "0";
								}
							//loop thru all the rate data and create rows
							
							//handles if there are no rate rows yet
							if(typeof(row.min) == 'undefined' || row.min==null){
								row.min=[];
							}

							console.log('rate row');
							console.log(row);
							
							var html = '';
							for(var i=0; i<row.rates.length; i++){

								shippingType = generate_shipping_type_html(row.rates[i].shippingType);
								shippingClass = generate_shipping_class_html(row.rates[i].shippingClass);
								shippingCondition = generate_condition_html(row.rates[i].shippingCondition);

								//default undefined or blank to zero
								if( typeof(row.rates[i].shipping) == 'undefined'){
									row.rates[i].shipping = 0;
								}
								
								if( typeof(row.rates[i].perItem) == 'undefined'){
									row.rates[i].perItem = 0;
								}
								
								if( typeof(row.rates[i].perWeight) == 'undefined'){
									row.rates[i].perWeight = 0;
								}
								
								html += '\
									<tr>\
										<td>\
											<input type="checkbox" class="jem-rate-checkbox" id="' + lastID + '"></input>\
										</td>\
										<td>\
										<select name="' + type + '" class="rate-type-select">\
											' + shippingType +'\
										</select>\
										</td>\
										<td>\
										<select name="' + cls + '" class="rate-class-select-select">\
											' + shippingClass+'\
										</select>\
										</td>\
										<td>\
										<select name="' + condition + '" class="rate-condition-select">\
											' + shippingCondition +'\
										</select>\
										</td>\
										<td>\
											<input type="text" size="10" placeholder="" name="' + min + '" value="' + row.rates[i].min + '"></input>\
										</td>\
										<td>\
											<input type="text" size="10" placeholder="" name="' + max + '" value="' + row.rates[i].max + '"></input>\
										</td>\
										<td>\
											<input type="text" size="10" placeholder="" name="' + shipping + '" value="' + row.rates[i].shipping + '"></input>\
										</td>\
										<td>\
											<input type="text" size="10" placeholder="" name="' + perItem + '" value="' + row.rates[i].perItem + '"></input>\
										</td>\
										<td>\
											<input type="text" size="10" placeholder="" name="' + perWeight + '" value="' + row.rates[i].perWeight + '"></input>\
										</td>\
								</tr>\
								';
							
								
								
							}
							
							
							return html;
						}	
					
						/**
						 * Handles the expansion contraction of the rate table for the zone
						 */	
						function expand_contract(){
					
							var row = jQuery(this).parent('td').parent('tr').next();
							
							if(jQuery(row).hasClass('jem-hidden-row')){
								jQuery(row).removeClass('jem-hidden-row').addClass('jem-show-row');	
								jQuery(this).removeClass('expand-icon').addClass('collapse-icon');							
							} else {
								jQuery(row).removeClass('jem-show-row').addClass('jem-hidden-row');																
								jQuery(this).removeClass('collapse-icon').addClass('expand-icon');							
							}
							
							
							
						}
						



						//**************************************
						// Generates the HTML for the SHIPPING TYPE
						// select. A value is passed in to 
						// determine which ones are selected
						//**************************************
						function generate_shipping_type_html(val){
											
							html = '<option value="xxx">None</option>';

							for(var i=0; i<shipping_types.length; i++){
								
								if(shipping_types[i] == val){
									//we have a match
									html += '<option value="' + shipping_types[i] + '" selected="selected">' + shipping_types[i] + '</option>'; 
								} else {
									html += '<option value="' + shipping_types[i] + '">' + shipping_types[i] + '</option>'; 
									
								}
							}
							
							return html;
						}
						
						//**************************************
						// Generates the HTML for the SHIPPING CLASS
						// select. A value is passed in to 
						// determine which ones are selected
						//**************************************
						function generate_shipping_class_html(val){
											
							//html = '<option value="any">Any Class</option><option value="none">No Class Set</option>';
							html = '';
							
							for(var i=0; i<shipping_class_array.length; i++){
								
								if(shipping_class_array[i].slug == val){
									//we have a match
									html += '<option value="' + shipping_class_array[i].slug + '" selected="selected">' + shipping_class_array[i].name + '</option>'; 
								} else {
									html += '<option value="' + shipping_class_array[i].slug + '">' + shipping_class_array[i].name + '</option>'; 
									
								}
							}
							
							return html;
						}
						
						//**************************************
						// Generates the HTML for the country
						// select. Uses an array of keys to
						// determine which ones are selected
						//**************************************
						function generate_country_html(keys){
											
							html = "";
							
							for(var key in country_array){
								
								if(keys.indexOf(key) != -1){
									//we have a match
									html += '<option value="' + key + '" selected="selected">' + country_array[key] + '</option>'; 
								} else {
									html += '<option value="' + key + '">' + country_array[key] + '</option>'; 
									
								}
							}
							
							return html;
						}
						
						
						//**************************************
						// Generates the HTML for the CONDITION
						// select. Uses an array of keys to
						// determine which ones are selected
						//**************************************
						function generate_condition_html(val){
											
							html = "";
							
							for(var key in condition_array){
								
								if( key == val){
									//we have a match
									html += '<option value="' + key + '" selected="selected">' + condition_array[key] + '</option>'; 
								} else {
									html += '<option value="' + key + '">' + condition_array[key] + '</option>'; 
									
								}
							}
							
							return html;
						}



						//PRO STUFF

						//*********************************************
						// Generates the HTML for the Zone Type Select
						// The value to be selected is passed in
						//*********************************************
						function generate_zone_type_html(zoneType){
											
							html = "";
							
							for(var key in zone_type_array){
								
								if(zoneType == key){
									//we have a match
									html += '<option value="' + key + '" selected="selected">' + zone_type_array[key] + '</option>'; 
								} else {
									html += '<option value="' + key + '">' + zone_type_array[key] + '</option>'; 
									
								}
							}
							
							return html;
						}
												
						//*********************************************
						// Generates the HTML for the Zone Value multi-Select
						// The value to be selected is passed in
						//*********************************************
						function generate_zone_value_html(zoneType, values){
											
							html = "";

							var arr = [];
							
							//the value is dependant on what kind of zone type has been
							// selected. Zips and states have the dropdown AND a value box
							// Countries ONLY have the value box
							
							switch(zoneType){
							case "country":
								return; 
								break;

							case "zip":
								break;

							case "state":
								break;
							}
							
							for(var key in zone_type_array){
								
								if(keys.indexOf(key) != -1){
									//we have a match
									html += '<option value="' + key + '" selected="selected">' + country_array[key] + '</option>'; 
								} else {
									html += '<option value="' + key + '">' + country_array[key] + '</option>'; 
									
								}
							}
							
							return html;
						}
												
						//***************************
						// Handle add/delete clicks
						//***************************

						//ZONE TABLE
						
						
						/*
						* add new ZONE row
						*/
						var zoneID = "#" + pluginID + "_settings";

						jQuery(zoneID).on('click', '.add-zone-buttons a.add', function(){
							
							//ok lets add a row!
							
							
							//var id = "#" + pluginID + "_settings table tbody tr:nth-last-child(3)";
							//create empty row
							var row = {};
							row.key = "";
							row.min = [];
							row.rates = [];
							row.condition = [];
							row.countries = [];
							row.zone_country = [];
							
							//add it before the default zonr
							jQuery('#jem-default-zone').before(create_zone_row(row));

							//turn on select2 for our row
							if (jQuery().chosen) {
								jQuery("select.chosen_select").chosen({
									width: '350px',
									disable_search_threshold: 5
								});


								jQuery("select.zone-values").chosen({
									width: '350px',
									disable_search_threshold: 5
								});
																
							} else {
								jQuery("select.chosen_select").select2();
								jQuery("select.zone-values").select2();
							}

							//now we need to fake a zone-type change so it sets up correctly...
							
							var thisRow = jQuery('#jem-default-zone').prev().prev().find('.zone-type-select');
							zone_type_changed(thisRow);
							
							return false;
						});
						
						/**
						 * Delete ZONE row
						 */
						jQuery(zoneID).on('click', '.add-zone-buttons a.delete', function(){
		
							//loop thru and see what is checked - if it is zap it!
							var rowsToDelete = jQuery(this).closest('table').find('.jem-zone-checkbox:checked');
							
							jQuery.each(rowsToDelete, function(){
								
								var thisRow = jQuery(this).closest('tr');
								//first lets get the next sibl;ing to this row
								var nextRow = jQuery(thisRow).next();
								
								//it should be a rate row
								if(jQuery(nextRow).hasClass('jem-rate-holder')){
									//remove it!
									jQuery(nextRow).remove();
								} else {
									//trouble at mill
									return;
								}
								
								jQuery(thisRow).remove();
							});
							
							//TODO - need to delete associated RATES
														
							return false;
						});
						
												
						//RATE TABLES
						
						/**
						* ADD RATE BUTTON
						*/
						jQuery(zoneID).on('click', '.add-rate-buttons a.add', function(){
							
							//we need to get the key of this zone - it's in the name of of the button
							var name = jQuery(this).attr('name');
							name = name.substring(4);
							
							//remove key_ 
							//ok lets add a row!
							

							var row = create_rate_row(name, null);
							jQuery(this).closest('tr').before(row);
							
							return false;
						});
					
						/**
						 * Delete RATE roe
						 */	
						jQuery(zoneID).on('click', '.add-rate-buttons a.delete', function(){

							//loop thru and see what is checked - if it is zap it!
							var rowsToDelete = jQuery(this).closest('table').find('.jem-rate-checkbox:checked');
							
							jQuery.each(rowsToDelete, function(){
								jQuery(this).closest('tr').remove();
							});
							
														
							return false;
						});
						
						//These handle building the select arras
						
						
							<?php
						   			echo "jQuery('#{$this->id}_settings').on('click', '.jem-expansion', expand_contract) ;\n";

						   	?>
					</script>
					
					<?php
					return ob_get_clean();		
				}  //end generate_table_rates_html

				function generate_shipping_class_table_html() {
					ob_start();
					
					?>
					<tr>
						<th scope="row" class="titledesc"><?php _e( 'Shipping Types', JEM_DOMAIN ); ?></th>
						<td id="<?php echo $this->id; ?>_shipping_types">
							<table class="shippingrows widefat">
						        <col style="width:0%">
						        <col style="width:100%;">
								<thead>
									<tr>
										<th class="check-column"></th>
										<th><?php _e( 'Shipping Types', JEM_DOMAIN ); ?> <a class="tips" data-tip="<?php _e( 'Your custom shipping type e.g. Standard, Overnight, Express Mail', JEM_DOMAIN ); ?>">[?]</a></th>

									</tr>
								</thead>
								<tbody style="border: 1px solid black;">
									<tr style="border: 1px solid black;">
										<td colspan="5" class="add-type-buttons">
											<a href="#" class="add button"> <?php _e('Add New Shipping Type', JEM_DOMAIN) ?></a>
											<a href="#" class="delete button"><?php  _e('Delete Selected Type', JEM_DOMAIN) ?></a>
										</td>
									</tr>
								</tbody>
							</table>
						</td>
					</tr>
					
					<script>


					//This loads any existing data in the options
					<?php
					
						//it's possible there are no shipping types
						$shipping_types = array();
						if ( isset( $this->options['shipping-types'] ) ) $shipping_types = $this->options['shipping-types'];
						
						foreach($shipping_types as $key => $value){
							
								//get the shipping type value;
								$val = json_encode($value);
								echo "jQuery('#{$this->id}_shipping_types table tbody tr:last').before(create_type_row({$val}));\n";
						}
						

				   	?>


					   	
						//Save the id
						var typesID =  <?php echo '"' . $this->id . '"'; ?>;
						
						//***********************************************
						//Handles the ADD SHIPPING TYPE BUTTON pressed 
						//***********************************************
						jQuery('#' + typesID + "_shipping_types").on('click', '.add-type-buttons a.add', function(){
							console.log('add clicked');
							//ok lets add a row!
							
							//Get the LAST table row which contains the buttons
							var id = "#" + pluginID + "_shipping_types table tbody tr:last";
							//create empty row
							jQuery(id).before(create_type_row(""));

							
							return false;
						});


						//***************************************************
						// Handles DELETE SHIPPING TYPE button
						//***************************************************
						jQuery('#' + typesID + "_shipping_types").on('click', '.add-type-buttons a.delete', function(){
								
							//loop thru and see what is checked - if it is zap it!
							var rowsToDelete = jQuery(this).closest('table').find('.jem-type-checkbox:checked');
							
							jQuery.each(rowsToDelete, function(){
								
								var thisRow = jQuery(this).closest('tr');
								
								jQuery(thisRow).remove();
							});
							
														
							return false;
						});						
						
						//*********************************************************************
						//This creates a shipping type row
						//If null is passed we create an empty on otherwise we use the data
						//*********************************************************************
						function create_type_row(val){
							console.log(val);
							var html = '<tr><td><input type="checkbox" class="jem-type-checkbox" id="" name="shipping-type-checkbox[]" ></input></td>';
							html += '<td><input type="text" size="20" placeholder="" name="shipping-type[]" value="' + val + '"></input></td></tr>';							
							return html;
							
						}
						
						
					</script>
					<?php
					return ob_get_clean();
				}

				//*********************
				// PHP functions
				//***********************

				
				//This initialises the arrays that generate the select HTML
				function create_select_arrays(){
					
					//first the CONDITION html
					$this->condition_array = array();
					$this->condition_array['weight'] = sprintf(__( 'Weight (%s)', JEM_DOMAIN ), get_option('woocommerce_weight_unit'));
			   		$this->condition_array['total'] = sprintf(__( 'Total Price (%s)', JEM_DOMAIN ), get_woocommerce_currency_symbol());

			   		// v1.2.2 - Added itemcount parameter 
			   		$this->condition_array['itemcount'] = sprintf(__( 'Item Count', JEM_DOMAIN ));
					

					//Now the countries
					$this->country_array = array();
					
			   		// Get the country list from Woo....
					foreach (WC()->countries->get_shipping_countries() as $id => $value) :
		   				$this->country_array[esc_attr($id)] = esc_js($value);
					endforeach;		

					//ZONE TYPES
					
					$this->zone_type_array['country'] = __( 'Country', JEM_DOMAIN );
					$this->zone_type_array['state'] = __( 'States', JEM_DOMAIN );
					$this->zone_type_array['zip'] = __( 'Zip/Postal Code', JEM_DOMAIN );
					
					//lets load ALL the states - how many???!!!
					$this->states_array = array();
					foreach (WC()->countries->get_shipping_countries() as $id => $value) :
						$this->states_array[esc_attr($id)] = WC()->countries->get_states($id);
					endforeach;

					
					array_push( $this->shipping_class_array, WC()->shipping->get_shipping_classes() );
					//Woo returns a fundky array of of array of object, the first array is always 1 element, lets fix that!!
					$this->shipping_class_array = $this->shipping_class_array[0];

					//now lets add our 2 default shipping classes
					$obj = new stdClass;
					$obj->name =  __( 'Any Class', JEM_DOMAIN );
					$obj->slug = "any";
					array_unshift($this->shipping_class_array, $obj);
					$obj = new stdClass;
					$obj->name =  __( 'No Class Set', JEM_DOMAIN );
					$obj->slug = "none";
					array_unshift($this->shipping_class_array, $obj);
						
				}


				
 				/**				 
				* This generates the select option HTML for teh zones & rates tables
				*/
				function create_select_html(){
					//first the CONDITION html
					$arr = array();
					$arr['weight'] = sprintf(__( 'Weight (%s)', JEM_DOMAIN ), get_option('woocommerce_weight_unit'));
			   		$arr['total'] = sprintf(__( 'Total Price (%s)', JEM_DOMAIN ), get_woocommerce_currency_symbol());

			   		// v1.2.2 - Added itemcount parameter 
			   		$arr['itemcount'] = __( 'Item Count', JEM_DOMAIN );
					   
					//now create the html from the array
					$html= '';
					foreach ($arr as $key => $value) {
						$html .= '<option value=">' . $key . '">' . $value . '</option>'; 
					}
					
					$this->condition_html = $html;
					
					$html = '';
					$arr = array();
					//Now the countries
					
			   		// Get the country list from Woo....
					foreach (WC()->countries->get_shipping_countries() as $id => $value) :
		   				$arr[esc_attr($id)] = esc_js($value);
					endforeach;							
					
					//And create the HTML
					foreach ($arr as $key => $value) {
						$html .= '<option value=">' . $key . '">' . $value . '</option>'; 
					}

					$this->country_html = $html;					
					
				}				


				//I don't think this is used!!!!
				//Creates the HTML options for the selected
				
// 				function create_dropdown_html($arr){
					
// 					$arr = [];
					

					
// 					$this->condition_html = html;
// 				}
										
				/**
				 * Create dropdown options 
				 */
				function create_dropdown_options() {
				
					$options = array();
				
		   		
			   		// Get the country list from Woo....
					foreach (WC()->countries->get_shipping_countries() as $id => $value) :
		   				$options['country'][esc_attr($id)] = esc_js($value);
					endforeach;
					
					// Now the conditions - cater for language & woo
			   		$option['condition']['weight'] = sprintf(__( 'Weight (%s)', JEM_DOMAIN ), get_option('woocommerce_weight_unit'));
			   		$option['condition']['price'] = sprintf(__( 'Total (%s)', JEM_DOMAIN ), get_woocommerce_currency_symbol());

			   		// v1.2.2 - Added itemcount parameter 
			   		$option['condition']['itemcount'] = __( 'Item Count', JEM_DOMAIN );
			   		
			   		return $options;
				}	

				
				/**
				* This saves all of our custom table settings
				*/
				function process_custom_settings() {
					
					//Arrays to hold the clean POST vars
					$keys = array();
					$zone_name =array();
					$zone_type = array();
					$zone_country = array();
					$zone_values = array();
					
					$rate_type = array();
					$rate_class = array();
					$rate_condition = array();
					$min = array();
					$max = array();
					$shipping = array();
					$perItem = array();
					$perWeight = array();
					$default_zone = array();
					
					
					$shipping_types = array();

					
					
					//Move the default zone fields into thier own space!
					//TODO should move this into a loop of variable names!
					if ( isset( $_POST[ 'default-rate-type-select'] ) ){
						$default_zone['rate-type-select'] = $_POST['default-rate-type-select'] ;
					}
						
					if ( isset( $_POST[ 'default-rate-class-select'] ) ){
						$default_zone['rate-class-select'] = $_POST['default-rate-class-select'] ;
					}
						
					if ( isset( $_POST[ 'default-rate-condition-select'] ) ){
						$default_zone['rate-condition-select'] = $_POST['default-rate-condition-select'] ;
					}
						
					if ( isset( $_POST[ 'default-min'] ) ){
						$default_zone['min'] = $_POST['default-min'] ;
					}
						
						
					if ( isset( $_POST[ 'default-max'] ) ){
						$default_zone['max'] = $_POST['default-max'] ;
					}
					
					if ( isset( $_POST[ 'default-shipping']) ){
						$default_zone['shipping'] = $_POST['default-shipping'] ;
					}
						
					if ( isset( $_POST[ 'default-per-item']) ){
						$default_zone['perItem'] = $_POST['default-per-item'] ;
					}
						
					if ( isset( $_POST[ 'default-per-weight']) ){
						$default_zone['perWeight'] = $_POST['default-per-weight'] ;
					}
						
					//Take the POST vars, clean em up and put thme in nice arrays 
					if ( isset( $_POST[ 'key'] ) ) $keys = array_map( 'wc_clean', $_POST['key'] );
					if ( isset( $_POST[ 'zone-name'] ) ) $zone_name = array_map( 'wc_clean', $_POST['zone-name'] );
					if ( isset( $_POST[ 'zone-type'] ) ) $zone_type = array_map( 'wc_clean', $_POST['zone-type'] );
					if ( isset( $_POST[ 'zone-country'] ) ) $zone_country = array_map( 'wc_clean', $_POST['zone-country'] );
						
					
					if ( isset( $_POST[ 'condition'] ) ) $condition = array_map( 'wc_clean', $_POST['condition'] );

					//no wc_clean as multi-D arrays
					if ( isset( $_POST[ 'zone-values'] ) ) $zone_values = $_POST['zone-values'] ;
					if ( isset( $_POST[ 'shipping-type'] ) ) $shipping_types = $_POST['shipping-type'] ;
					
					//These are the rate fields
					if ( isset( $_POST[ 'rate-type-select'] ) ) $rate_type = $_POST['rate-type-select'] ;
					if ( isset( $_POST[ 'rate-class-select'] ) ) $rate_class = $_POST['rate-class-select'] ;
					if ( isset( $_POST[ 'rate-condition-select'] ) ) $rate_condition = $_POST['rate-condition-select'] ;
					if ( isset( $_POST[ 'min'] ) ) $min = $_POST['min'] ;
					if ( isset( $_POST[ 'max'] ) ) $max = $_POST['max'] ;
					if ( isset( $_POST[ 'shipping'] ) ) $shipping = $_POST['shipping'] ;
					if ( isset( $_POST[ 'per-item'] ) ) $perItem = $_POST['per-item'] ;
					if ( isset( $_POST[ 'per-weight'] ) ) $perWeight = $_POST['per-weight'] ;
						
					

					//TODO - need to add soem validation here and some error messages???
					
				
					
					//Master var of options - we keep it in one big bad boy
					$options = array();
					
					//OK we need to loop thru all of them - the keys will help us here - process by key
					foreach($keys as $key => $value){
						
						
						//we only process it if a name & type are set
						if(
							empty($zone_name[$key]) ||
							empty($zone_type[ $key ]) 
							){
							//something is empty so don't save it
							continue;
							
						}
						
						
						//Get the zone name - this is our main key
						$name =  $zone_name[$key];
						
						
						//cater for empty fields
						if(!isset($zone_values[ $key ] )){
							$zone_values[ $key ] = ''; 
						}

						//If we don't have any rate rows then just make it empty so we don't get an undefined error
						if(!isset($min[ $key ])){
							$min[ $key ] = array();
						}
						
						//Going to add the rates now.
						//before we do that check if we have any empty rows and delete them
						$obj = array();
						foreach ($min[ $key ] as $k => $val) {
    							if(
									empty($min[ $key ][$k]) &&
									empty($max[ $key ][$k]) &&
									empty($shipping[ $key][$k]) 
								)
								{
									unset($min[ $key ][$k]);
									unset($max[ $key ][$k]);
									unset($shipping[ $key ][$k]);
								}
								else {
									
									//blanks for the base, per item & per weight should be converted to zero if they are empty
									if( !is_numeric($shipping[ $key ][ $k])){
										$shipping[ $key ][ $k] = "0";
									}
									
									if( !is_numeric($perItem[ $key ][ $k])){
										$perItem[ $key ][ $k] = "0";
									}
									

									if( !is_numeric($perWeight[ $key ][ $k])){
										$perWeight[ $key ][ $k] = "0";
									}
									
									//add it to the object array
									$obj[] = array("shippingType" => $rate_type[ $key ][ $k ], 
													"shippingClass" => $rate_class[ $key ][ $k], 
													"shippingCondition" => $rate_condition[ $key ][ $k], 
													"min" => $min[ $key ][ $k], 
													"max" => $max[ $key ][ $k], 
													"shipping" => $shipping[ $key ][ $k],
													"perItem" => $perItem[ $key ][ $k],
													"perWeight" => $perWeight[ $key ][ $k]
												
									);									
								}
									
						}		
						
						//OK now lets sort or array of objects!!
						//usort($obj, 'self::cmp');
						// Obtain a list of columns
						
						$type = array();
						$class = array();
						$condition = array();
						$min_sort = array();
						
						foreach ($obj as $k => $row) {
							$type[$k]  = $row['shippingType'];
							$class[$k]  = $row['shippingClass'];
							$condition[$k]  = $row['shippingCondition'];
							$min_sort[$k]  = $row['min'];
								
						}
						
						//its possible we have no rows! In which case the sort will throw an error so lets skip it
						if(count($obj) != 0){
							// Sort the data 
							array_multisort($type, SORT_ASC, $class, SORT_ASC, $condition, SORT_ASC, $min_sort, SORT_ASC, $obj);
						}
						

						
						//create the array to hold the data				
						$options[ $name ] = array();
						
						$options[ $name ][ 'zone_type'] = $zone_type[ $key ]; 
						$options[ $name ][ 'zone_country'] = $zone_country[ $key ]; 
						$options[ $name ][ 'zone_values'] = $zone_values[ $key ]; 
						$options[ $name ][ 'rates'] = $obj;			//This is the sorted rates object!
						
						
						
					}

					//The shipping types rows
					$types = $shipping_types;
						

					//Sort the default zone
// 					$type = [];
// 					$class = [];
// 					$condition = [];
// 					$min = [];
// 					foreach ($default_zone as $k => $row) {
// 						$type[$k]  = $row['rate-type-select'];
// 						$class[$k]  = $row['rate-class-select'];
// 						$condition[$k]  = $row['rate-condition-select'];
// 						$min[$k]  = $row['min'];					
// 					}
// 					// Sort the data
// 					array_multisort($type, SORT_ASC, $class, SORT_ASC, $condition, SORT_ASC, $min, SORT_ASC, $default_zone);
						
					
					//SAVE IT
					$new_options = array();
					$new_options['rates'] = $options;
					$new_options['shipping-types'] = $shipping_types;
					$new_options['default-rates'] = $default_zone;
						
					//update_option( $this->option_key, $options ); 
					update_option( $this->option_key, $new_options ); 
				}	
				
				
				/**
				* This RETIEVES  all of our custom table settings
				*
				*/
				function get_options() {
					
					//Retrieve the zones & rates
					$this->options = array_filter( (array) get_option( $this->option_key ) );
					
					//lets account for the first time and if some fields are not set make them empty arrays
					if(! isset($this->options['shipping-types'])){
						$this->options['shipping-types'] = array();
					}
					
					$x = 5;
				}	
				
				/**
				 * calculate_shipping function. Woo calls this automagically
				 *
				 */
				public function calculate_shipping( $package= Array()  ) {
					
					
					
					
					
					//what is the tax status
					if ($this->settings['tax_status'] == 'notax') {
						$taxes = false;
					} else {
						$taxes = true;
					}
					
					
					
					
					//test just to get a value out there....
					$cost= 1;
					
					//ok first lets get the country that this order is for
					$dest_country = $package['destination']['country'];
					$dest_state = $package['destination']['state'];
					$dest_zip = $package['destination']['postcode'];

					
					//lets see if any zones match this addre
					$zones = $this->find_zones($dest_country, $dest_state, $dest_zip);

					//Lets group by and sum the cart by shipping class. We need to sum weight & total cost
						
					$cart_grouped = $this->group_cart_by_class($package['contents']);
						
					//If we didn't get anything returned then check the default zone (as long as there is something in it)
					//1.1 updated to handle empty but NO defaults!!
					if(empty($zones)){

						if(isset($this->options['default-rates']['rate-type-select'])){
						
						
						
						//create the default zone set of rates - this gets passed into the check_rates function
						//TODO in the future we should just save it in the same format so we can avoid this. Next version
						$def = array();
						foreach($this->options['default-rates']['rate-type-select'] as $k => $v){
							$temp = array();
							$temp['shippingType'] = $this->options['default-rates']['rate-type-select'][$k];
							$temp['shippingClass'] = $this->options['default-rates']['rate-class-select'][$k];
							$temp['shippingCondition'] = $this->options['default-rates']['rate-condition-select'][$k];
							$temp['min'] = $this->options['default-rates']['min'][$k];
							$temp['max'] = $this->options['default-rates']['max'][$k];
							$temp['shipping'] = $this->options['default-rates']['shipping'][$k];
							$temp['perItem'] = $this->options['default-rates']['perItem'][$k];
							$temp['perWeight'] = $this->options['default-rates']['perWeight'][$k];
						
							array_push($def, $temp);
						
						}
						
						//ok we have rates now so lets do the match on default
						$def_rates = array();
						$def_rates[0]['rates'] = $def;
						
						$rates = $this->check_rates($dest_country, $dest_state, $dest_zip, $def_rates, $cart_grouped);
						} else {
							//1.1 - empty and NO default - just return..
							return;
							
							
						}
						
					} else {
						//OK we have a match on country, state or zip!
	
						
						
						//lets see if any of these zones have rates that satisfy this cart
	
						
						$rates = $this->check_rates($dest_country, $dest_state, $dest_zip, $zones, $cart_grouped);
					}
					
					
					
					//Now add the rates
					foreach($rates as $k => $v){

						//If the label is 'xxx' it means it is the default one so lets get the one set in the options
						// otherwise use the one supplied
						if($k == 'xxx'){
							$title = $this->title;
						} else {
							$title = $k;
						}
						
						//add on the handling fee!
							
						//chek it is valid first
						if(is_numeric($this->settings['handling_fee'])){
							$v += $this->settings['handling_fee'];
						}
						
						
						$rate = array(
								'id' => $k,
								'label' => $title,
								'cost' => $v,
								'calc_tax' => ''
								
						);
						
						// Register the rate
						$this->add_rate( $rate );
					}
					
					
					return;
						
					
					
					
					
						
					//OK we have valid rates for the country, now lets find the appropriate entry....
					//We assume the user entered the rates ocrrectly..

					if($rates[0]['condition'] == 'total'){
						//price based comparisons
						$cost = $this->find_matching_rate(WC()->cart->cart_contents_total, $rates);
					} else {
						//weight based comparison
						$cost = $this->find_matching_rate(WC()->cart->cart_contents_weight, $rates);
					}
					
					//if we got nothing back then there is no match in this case, we just return without an object and
					// this option disapears
				
					if($cost==null){
						return;		
					}
					

					
					$rate = array(
						'id' => $this->id,
						'label' => $this->title,
						'cost' => $cost,
						'taxes' => $taxes,
						'calc_tax' => 'per_order'
					);

					// Register the rate
					$this->add_rate( $rate );
				}
				
				
				//****************************************************************
				//Pro function - lets find all the applicable zones for an addr
				//TODO - thisnk about if we should only match the first one???
				//****************************************************************
				function find_zones($country, $state, $zip){
					
    					$matchingZones = array();
					
					//1.1 - if we don't have any rates then lets just return
					if(!isset($this->options['rates'] )){
						return;
					}
					
					//ok loop thru all the zones and then compare based on the type
					foreach($this->options['rates'] as $rate){
						
						//what type of rate do we have?
						
						switch ($rate['zone_type']){
							
							case "country":
								//check if this zone contains our country
								
								//loop thru all the zone_values
								foreach ($rate['zone_values'] as $key => $value){
									if($value == $country){
										
										array_push($matchingZones, $rate);
										break;
									}
								}
								
								break;
								
							case "state":
								
								//for state the country must match and then we need to match a state
								
								//does destination country match this zone country
								if($rate['zone_country'] == $country){
									//ok the country matches now is the state one of the ones in the array
									
									foreach ($rate['zone_values'] as $key => $value){
										if($value == $state){
											
											array_push($matchingZones, $rate);
											break;
										}
									}
								}
								break;
								
							case "zip":
								
								
								//cater for no zip
								if($zip ==""){
									break;
								}
								
								
								//break the text into an array byline
								$lines = explode("\r\n", $rate['zone_values']);
								
								//OK if it ends in \r\n then the last entry can be empty and we wat to delete it!
								
								if(end($lines) == ""){
									array_pop($lines);
								}
								
								//lets loop thru each line
								foreach($lines as $key => $line){

									//ok, first see if it contains a '-' and hence is a range
									if( strpos($line, "-") !== false){
										//ok lets get the LEFT and the RIGHT pieces of the range....
										$temp = explode( "-", $line, 2);
										
										$left = $temp[0];
										$right = $temp[1];
										
										//OK now for a range comparison!
										if( (strcasecmp($zip, $left)>= 0) && (strcasecmp($zip, $right)<= 0) )  {
											array_push($matchingZones, $rate);
											break 2;  //exit foreach AND switch
										}
										
										
									} else {
										//it does NOT contain a - so it means the zip needs to START WITH to be a match
										
										if( strpos($zip, $line) === 0){
											//we have a match so this is a GOOD zone
											array_push($matchingZones, $rate);
											break 2; //exit foreach AND switch												
										}
									}
									
									
								}

								break;
							
							
						}
						
					}
					
					return $matchingZones;
				}
				
				
				//****************************************************************
				// Go thru the cart and check each zone to see if it satisfies the cart
				// The cart items passed in are already grouped by shipping class - 
				// 0 - represents it doesn't have a shipping class, 1 represents ANY shipping class
				// We also need to take into account the shipping type
				// EVERY cart item needs to be handled in a shipping type for it to be valid
				// This is quite complex - most of the logic is here!!
				//****************************************************************
				function check_rates($country, $state, $zip, $zones, $cart_items){

			

					$ret_types = array();
					
					
					
					//Loop thru each zone
					foreach ($zones as $key => $zone){

						
						//This is our array which will hold the shipping cost per shipping type
						$shipping_cost = array();
						
						//first lets get the UNIQUE set of shipping types for this zone
						
						$unique_types = array();
						
						foreach($zone['rates'] as $rate){
							$unique_types[$rate['shippingType']] = "YES WE HAVE ONE";	
						}
						
						//OK now we have a unique list of shippingTypes lets loop thru each one
						

						foreach($unique_types as $shipping_type => $val){

							
							//This is the "NONE" bucket that keeps track of the items that don't have a shipping class
							$none_bucket = array();
							$none_bucket['cost'] = 0;
							$none_bucket['weight'] = 0;
							$none_bucket['qty'] = 0;
							$none_bucket['count'] = 0;
							
							//This is the "ANY" bucket that keeps track of the cart items that don't have a specific rate for them
							$any_bucket = array();
							$any_bucket['cost'] = 0;
							$any_bucket['weight'] = 0;
							$any_bucket['qty'] = 0;
							$any_bucket['count'] = 0;
								
							
							//Holds the shipping cost for this shipping type -1 means we don't have a match
							//Maybe refactor at a later date
							$shipping_cost[$shipping_type] = -1;
							
								
							//for this shipping type loop thru the items in cart 
							foreach($cart_items as $shipping_class => $item){
	
								//if this item doesn't have a class - add it to the NONE bucket
								if($shipping_class ===0){
									$none_bucket['cost'] += $item['total_cost'];
									$none_bucket['weight'] += $item['total_weight'];
									$none_bucket['qty'] += $item['qty'];
									$none_bucket['count'] += 1;
									continue;
								}
								
								//lets check if there is a rate in this zone that satisfies this cart item, for this shipping type
								
								$ret = $this->find_matching_rate($item, $shipping_class, $shipping_type, $zone['rates']);
	
								//If we didn't find anything then this cart item into the "ANY" shipping class 
								if($ret == -1){

									$any_bucket['cost'] += $item['total_cost'];
									$any_bucket['weight'] += $item['total_weight'];
									$any_bucket['qty'] += $item['qty'];
									$any_bucket['count'] += 1;
									continue;
								}
								
								//if we got this far then we found a match for this cart item(s) 
								//OK so lets add this shipping cost onto our total
								if($shipping_cost[$shipping_type] == -1){
									$shipping_cost[$shipping_type] = 0;
								}
								$shipping_cost[$shipping_type] += $ret;
									
								
							
							}  //end for each cart 
						

							//OK if we have some ANY or NONE then we need to process those as well....
							if($any_bucket['count'] > 0){
								//ok we need to see if there is an ANY rate that matches this bucket
								$any_item = array();
								$any_item['total_weight'] = $any_bucket['weight'];
								$any_item['total_cost'] = $any_bucket['cost'];
								$any_item['qty'] = $any_bucket['qty'];
								
								//find a match with the ANY shipping class
								$ret =  $this->find_matching_rate($any_item, 'any', $shipping_type, $zone['rates']);
								
								//if none found then this shipping type does not have a match for us...
								
								if($ret == -1 ){
									$shipping_cost[$shipping_type] = -1;
									continue;
								} else {
									//there was a match so add it iN!!!
									//if shipping is -1 set it to zero
									if($shipping_cost[$shipping_type] == -1){
										$shipping_cost[$shipping_type] = 0;
									}
									
									$shipping_cost[$shipping_type] += $ret;
								}
							}
							
							//OK now lets see of we have any items that are on the NONE shipping class
							if($none_bucket['count'] > 0){
								//ok we need to see if there is an ANY rate that matches this bucket
								$none_item = array();
								$none_item['total_weight'] = $none_bucket['weight'];
								$none_item['total_cost'] = $none_bucket['cost'];
								$none_item['qty'] = $none_bucket['qty'];
							
								//find a match with the ANY shipping class
								$ret =  $this->find_matching_rate($none_item, 'none', $shipping_type, $zone['rates']);
							
								//if none found then this shipping type does not have a match for us...
							
								if($ret == -1 ){
									$shipping_cost[$shipping_type] = -1;
									continue;
								} else {
									//there was a match so add it iN!!!
									if($shipping_cost[$shipping_type] == -1){
										$shipping_cost[$shipping_type] = 0;
									}
										
									$shipping_cost[$shipping_type] += $ret;
								}
							}
								
							
							
						}   // end for each shipping type

						//ok we have been thru each shipping type, lets go thru them and delete anything with a shipping cost of -1
						// as it means there was no match for it
						foreach ($shipping_cost as $k => $v){
							if($v >= 0){
								$ret_types[$k] = $v;
							}
						}

					}  // end for each zone
					
					return $ret_types;
					
					
				}
				
	
				
				//******************************************************************
				// This attempts to find a matching rate, if so it returns the
				// $$ cos
				//******************************************************************
				function find_matching_rate($item, $shipping_class, $shipping_type, $rates){
					
					//lets go thru each rate and see if we match
					$ret = -1;
					foreach($rates as $k => $v){

						//does the class & type match?
						if($v['shippingType'] != $shipping_type || $v['shippingClass'] != $shipping_class){
							continue;
						}
						
						//ok we have a match on class & type lets see if we are doing weight or price comparison
						// v1.2.2 - Added quantity comparison for itemcount parameter 
						if($v['shippingCondition'] == 'weight'){
							$target = $item['total_weight'];
						} else if($v['shippingCondition'] == 'itemcount'){
							$target = $item['qty'];
						} else {
							$target = $item['total_cost'];
						}
						
						//ok, so now does it fall between the min/max
						//need to account for unlimited in max *
						//we do a sneaky one, just add 1 to the target and put it in max - keeps the
						//rest of the code the same
						if($v['max'] === "*"){
							$v['max'] = $target + 1;
						} 
				
						if($target >= $v['min'] && $target <= $v['max']){
							//we have a match!!!!
							
							//so lets calc the shipping for this rate row
							
							//base amt to bgin with
							
							$calc = $v['shipping'];
							
							//now any item qty 
							$calc += $item['qty'] * $v['perItem'];
							
							//and finally per weight
							$calc += $item['total_weight'] * $v['perWeight'];
							
							//and that is how we do it
							//TODO CARRY ON HERE!!!!
						} else {
							//no match so continue
							continue;
						}
						
						//if we got to here it means we had a match - lets return it!
						$ret = $calc;
						break;
						
					}
					
					return $ret;
					
				
				}
				
					
				//******************************************************************
				// This groups the cart by shipping class, it will sum weight & cost & item count
				//******************************************************************
				function group_cart_by_class($cart){
					
					$results = array();
										
					foreach($cart as $cart_item){
						
						//First get the shipping class, for some reason not populated in the cart
						$shipping_class = $cart_item['data']->get_shipping_class();

						//if there is no class then use zero
						
						if($shipping_class == ""){
							$shipping_class = 0;	
						}
						
						//does an entry already exist for this shipping class
						if(array_key_exists($shipping_class, $results)){
							$results[$shipping_class]['total_cost'] += $cart_item['line_total'];
							$results[$shipping_class]['total_weight'] += $cart_item['data']->weight * $cart_item['quantity'];
							$results[$shipping_class]['qty'] += $cart_item['quantity'];
						} else {
							//doesn't exist so add it
							$results[$shipping_class]['total_cost'] = $cart_item['line_total'];
							$results[$shipping_class]['total_weight'] = $cart_item['data']->weight * $cart_item['quantity'];
							$results[$shipping_class]['qty'] = $cart_item['quantity'];
						}
						
					}
					
					return $results;
					
				}
				
				
				
				
	
			}
		}
	}
 
	add_action( 'woocommerce_shipping_init', 'jem_table_rate_init' );
 
	function add_jem_table_rate( $methods ) {
		$methods[] = 'JEM_Table_Rate_Shipping_Method_Pro';
		return $methods;
	}
 
	add_filter( 'woocommerce_shipping_methods', 'add_jem_table_rate' );
}


/**
 * Load admin scripts
 */
function jem_table_rate_admin_scripts( $hook ) {
    global $wptr_settings_page, $post_type;

    // Use minified libraries if SCRIPT_DEBUG is turned off
	$suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
	$suffix = "";
	
	

	//Load the styles & scripts we need 
    if ($hook == 'woocommerce_page_wc-settings') {

        wp_enqueue_script( 'jquery' );
        wp_enqueue_script( 'jquery-ui-core' );
        wp_enqueue_style( 'wpr_table_rate_admin_css', JEM_URL . 'assets/main' . $suffix . '.css' );
        
    }
}

add_action( 'admin_enqueue_scripts', 'jem_table_rate_admin_scripts', 100 );

//****************
//Languages
//****************
add_action('plugins_loaded', 'jem_table_rate_load_textdomain');
function jem_table_rate_load_textdomain() {
	load_plugin_textdomain( JEM_DOMAIN, false, dirname( plugin_basename(__FILE__) ) . '/languages/' );
	
}




