﻿
// GLOBALS
var footerX, footerY;
var icons = new Array();
var spinner;
var spinTarget;

// ON READY
$(function() {

	var opts = {
		lines: 10, // The number of lines to draw
		length: 8, // The length of each line
		width: 4, // The line thickness
		radius: 14, // The radius of the inner circle
		color: '#000', // #rgb or #rrggbb
		speed: 0.8, // Rounds per second
		trail: 57, // Afterglow percentage
		shadow: false // Whether to render a shadow
	};
	spinTarget = document.getElementById('subContain');
	spinner = new Spinner(opts);
		
	// EVENTS
	// check image validation
	$('input.file').change(function() 
	{
		var val = $(this).val();
		var privacy = 'C:\\fakepath\\';
		var ext = val.substring(val.length-3, val.length).toLowerCase();
		
		if (val.indexOf(privacy) != -1) // removes privacy string from chrome's file value
			val = val.substring(privacy.length, val.length);
		
		function error(err)
		{
			alert(err);
			$('input.fakefile').val('');
		}
		
		// Check for PNG or ICO (anything else?)
		if (ext == 'ico')
			return error("ICO to PNG is currently under maintenance, we're sorry for the inconvenience this may cause you");
		else if (ext != 'png')
			return error('File needs to have an extension type of .png or .ico');
		else if(val.indexOf('_previmg.png') > -1)
			return error("Filename cannot be '_previmg.png'");
		
		$('input.fakefile').attr('value',val);
		
	}).click(function() // apply selected UI/el.
	{
		$('input').removeClass('on');
		$(this).addClass('on');
		$('#selected').val('file');
		$('input.fakefile').addClass('on');
	});
	
	// check url validation
	// checking protocal but not domain or .com/etc
	$('input.text').change( function() 
	{
		var val = $(this).val();
		var find = ':';
		var loc = val.indexOf(find);
		var protocal = val.substring(0, loc).toLowerCase();
		
		// guessing http, https, and ftp should be the only supported protocals
		/*
		if (protocal != 'http' && protocal != 'https' && protocal != 'ftp')
			alert('NEED A PROPER URL!');
		else
		{
			// could make it proper? and then just go with http and hope they entered a URL that will work
		}
		*/	
		
	}).mousedown(function() // apply selected UI/el.
	{
		$('input').removeClass('on');
		$(this).addClass('on');
		$('#selected').val('remote');
		$('input.file').val(''); // must remove the file value or the URL will not be the converted image and it will upload the file image to the server anyways when uneeded
		$('input.fakefile').attr('value','');
	});
	
	$('#fConvert').ajaxForm({
		beforeSubmit: function() {
		
			var sel = $('#selected').val();
			if(sel == '')
				return false;
			else if(sel == 'file' && $('input.file').val() == '')
				return false;
			else if(sel == 'remote' && $('input.text').val() == 'http://')
				return false;
			
			spinner.spin();
			$('#subContain input').hide();
			$(spinner.el).css('left','43px').css('top', '80px');
			$('#subContain').append(spinner.el);
			
			userActive();
		},
		success: function(html) {
			debug.debug(html);
			spinner.stop(spinTarget);
			$('#subContain input').show();
			
			var ico = new icon( new iconInfo(html) );
			if (ico.valid())
			{
				icons.push( ico );
				ico.display();
				
				updateCounters(true);
			}
			else
				debug.debug('Invalid Icon Creation');
		}
	});	
	
	// END EVENTS
	
	// fixe for FF3.5 cache of file name value
	$('input.file').val('');
	$('input.fakefile').attr('value','');
	
	// Center Recents
	$('.iconslist img').each(function()
	{
		$(this).imagesLoaded(function()
		{
			centerElement(this);
		});
	});	
	
	refreshRate = determineRefreshRate();
	setTimeout(function(){ refreshRecent(); }, refreshRate);
	
	// No hash tag for the howto
	$('a.expand').click(function(evt) 
	{ 
		evt.preventDefault(); 
		var how = $('.how');
		
		$(how).toggle();
		var vis = $(how).css('display');
		
		if (vis == 'block')
			$('a.expand').text('Click to Close Instructions');
		else
			$('a.expand').text('Click Here for Instructions');
	});
	
});// END ON READY


/// OOP Stuff
// Classes
function iconInfo(data)
{
	var maxNameLen = 11;
	
	//	Methods (has to be declared above the try/catch maybe if I created a init function it might work out better though? Or could be called @ the end of the class
	this.issue = function(err)
	{
		this._valid = false;
		debug.debug(err);
	}
	this.showIssue = function(err)
	{
		this.issue(err);
		alert(err);
	}
	
	try
	{
		this.inst = $.parseJSON(data);
	}
	catch(err)
	{
	debug.debug(err);
		this.showIssue("There was an error Converting your Icon.  This is caused by utilizing images higher "+
						" than 200kb in size or images with huge height/width dimensions, corrupt data files or "+
						"bogus file formats. If you continue to experience this issue please write to info@proicons.com");
		//"There was a Fatal Error parsing the response. \nThis is most commonly because the image you uploaded has "+
		//	"too large of dimensions, or because there was an error in the service. \n\nIf you continue to experience this issue please "+
		//	"write to info at favico dot com \n\nERROR MESSAGE: "+err);
	}
	this._valid = true;
	
	// Accessors
	this.error = function()
	{
		return this.inst.error;
	}
	this.type = function()
	{
		return this.inst.type;
	}
	this.New = function()
	{
		return this.inst.New;
	}
	this.original = function()
	{
		return this.inst.original;
	}
	this.size = function()
	{
		return parseFloat(this.inst.size/1024).toFixed(1)
	}
	this.name = function()
	{
		return this.inst.name;
	}
	this.nameTrim = function()
	{
		if (this.name().length > maxNameLen)
			return this.name().substring(0, maxNameLen) + '...';
		else
			return this.name();
	}
	this.preview = function()
	{
		return this.inst.preview;
	}
	this.valid = function()
	{
		return this._valid;
	}
	this.errors = function()
	{
		var errs = this.error().length;
		if (errs > 0)
			return true;
		else 
			return false;
	}
		
	// check that our initialization of the object is fine
	if(!this.inst)
	{
		this.issue('IconInfo missing JSON data');
	}
	else if (this.errors())
	{
		var errs = this.error();
		for (err in errs)
		{
			alert(errs[err][1]);
			debug.debug(errs[err][1]);
		}
		this._valid = false;
	}
	else
	{
		if(!this.error())
			this.issue('IconInfo Missing Error');
		if(!this.type())
			this.issue('IconInfo Missing Type');
		if(!this.New())
			this.issue('IconInfo Missing New');
		if(!this.original())
			this.issue('IconInfo Missing Original');
		if(!this.size())
			this.issue('IconInfo Missing File Size');
		if(!this.name())
			this.issue('IconInfo Missing Name');
		if(!this.preview())
			this.issue('IconInfo Missing Preview');
	}
}

function icon(iIconInfo)
{
	this.info = iIconInfo;
	
	// wrapper method
	this.valid = function()
	{
		return this.info.valid();
	}
	
	// Methods
	this.display = function()
	{
		styleLast = function()
		{
			// give the last iconblock a the 'last' class if more than 1 icon
			var iconsInBlock = $('#results div.iconblock');
			$(iconsInBlock).removeClass('last'); // clear any for changes incase of removal
			if (iconsInBlock.length > 1)
				$(iconsInBlock[iconsInBlock.length-1]).addClass('last');
		}
		
		var html = $(''+
			'<div class="iconblock newest" style="display:none;">'+
			'  <div class="remove" title="Delete Icon">X</div>'+
			'  <div class="info">'+
			'    <span><img src="'+this.info.preview()+'"></span>'+
			'    <h5 title="'+this.info.name()+'">'+this.info.nameTrim()+'</h5>'+
			'    <p>'+this.info.size()+'KB / '+this.info.type()+'</p>'+
			'  </div>'+
			'  <div class="download">'+
			'    <a href="'+this.info.New()+'" title="Download This Icon">&#11015;</a>'+
			'  </div>'+
			'</div>');
		
		// No icons
		if ($("#noicons").length > 0)
			$('#noicons').remove();
		
		// remove any older iconblocks with the class 'newest'
		$('#results div.iconblock').removeClass('newest');
		$('#results').prepend(html);
		$('img', html).load(function() 
		{
			centerElement(this);
		});
		$('#results .newest').slideDown(); // animate
		
		styleLast();
		
		// Deletion/Removal event
		$('div.remove', html).click(function()
		{
			$(this).parent().fadeOut(0, function()
			{
				var icons = $('.iconblock');
				if (icons.length == 1)
				{
					html = ''+
					'<div id="noicons" style="display:none">'+
		           	' 	<h5>Start Converting Icons Now</h5>'+
		           	'     <p>Icons will appear here once you convert them</p>'+
		           	' </div>';
		           	
		            $('#results').prepend(html);
		            $('#noicons').fadeIn(2000);
				}
				else if ($(this).hasClass('newest') && icons.length > 1)
				{
					$(icons[1]).addClass('newest');
				}
				$(this).remove();
				
				styleLast();
			});
		});
	}
}

// Part of LIVE SITE AJAXING

function liveUpdate()
{
	this.json;
	this.html;
	this.total;
	this.hourly;
	
	this.update = function(json)
	{
		this.json = $.parseJSON(json);
		this.html = this.json[0];
		this.total = this.json[1];
		this.hourly = this.json[2];
	}
}

// End Classes
	
// END OOP Stuff


// LIVE SITE AJAXING

var refreshRate;// found using determineRefreshRate() (has a maximum of 5 seconds) = 5*1000;// 5 seconds
var timeOut = 36; // how many refreshes before quitting 5*36 = 180 seconds = 3 minutes
var refreshes = 0; // count how many times we've refreshed
var lastUpdate = new liveUpdate();

function update(callback)
{
	$.ajax({
		url: 'newest.php',
		data: 'ajax&time='+getTimeFromSrc( $($('.iconslist img')[0]).attr('src') ),
		success: function( html ) 
		{
			//debug.debug(html);
			lastUpdate.update(html);
			callback();
		}	
	});
}

function refreshRecent()
{
	update( function()
	{
		var html = lastUpdate.html;
		
		var imgSrc1 = $($('.iconslist img')[0]).attr('src');
		var imgSrc2 = $($('img', html)[0]).attr('src');
		
		// only do the fancy fade in/out if there's a change in content, The image's source contains a timestamp ;) issue with comparing html is that current html will have styling
		if (imgSrc1 != imgSrc2) 
		{
			var count = $('img', html).length;
			var cWidth = 48+10; // width + margin right
			var width = cWidth*count;
			
			$('.iconslist').css('margin-left', '-'+width+'px');
			$('.iconslist').prepend(html);
			
			$('.iconslist img').each(function()
			{
				$(this).imagesLoaded(function() {
					centerElement(this);
				});
			});
			
			$('.iconslist img').imagesLoaded(function() 
			{
				$('.iconslist').animate({'margin-left': '0px'}, 1000, function()
				{
					// Remove images not seen anymore from the DOM in hopes
					//  that it will help save memory if the browser GC's properly
					
					var imgs = $('.iconslist img');
					var c = imgs.length;
					
					// Sanitity test although shouldn't get here if there were only 8 images in after a proper update along with the time checks
					if (c > 8)
					{
						//debug.debug('CLEANUP c='+c);
						for (i = 8; i < c; i++)
						{
							$(imgs[i]).parent().remove();
						}
					}
				});
			}); // END $('.iconslist img').imagesLoaded
		}
		//else
		//	debug.debug('SKIPPED UPDATE');
		
		updateCounters(false);
		
		refreshes++;	
		if (refreshes < timeOut)
		{
			// update refresh rate, although it shouldn't really change much hourly per refresh, but incase a resumed session
			//  could be thrown into userActive()
			refreshRate = determineRefreshRate(); 
			setTimeout(function() { refreshRecent(); }, refreshRate);
		}
	});
}

function getTimeFromSrc(src)
{
	var toFind1 = "/images/";
	var toFind2 = "/_previmg.png";
	var loc1 = src.indexOf(toFind1);
	var loc2 = src.indexOf(toFind2);
	
	var len = src.length;
	var len1 = toFind1.length;
	var len2 = toFind2.length;
	
	loc1 += len1;
	
	src = src.substr(loc1, len - (len1 + len2));
	return src;
}

function updateCounters(addOne)
{
	var counterTotal = $('#counter span.total');
	var counterHourly = $('#counter span.hour');
	
	total = lastUpdate.total;
	hourly = lastUpdate.hourly;
	
	$(counterTotal).html(total);
	$(counterHourly).html(hourly);

	if (addOne)
	{
		// add one to the counters ;)
		var cNumT = stripNonNumeric( $(counterTotal).html() );
		var cNumH = stripNonNumeric( $(counterHourly).html() );
		
		cNumT ++;
		cNumH ++;
		
		cNumT = addCommas(cNumT);
		cNumH = addCommas(cNumH);
		
		$(counterTotal).html(cNumT);
		$(counterHourly).html(cNumH);
	}
}

// Resets the amount of refreshes, or will renable a timed out live session
function userActive()
{
	if (refreshes >= timeOut)
	{
		setTimeout(function() { refreshRecent(); }, refreshRate);

	}
	refreshes = 0;
}

function determineRefreshRate()
{
	var perHr = $('#counter span.hour').html();
		perHr = stripNonNumeric(perHr);
	var secsInHr = 60*60;
	var rate = secsInHr / perHr * 1000; // need in millisecs
	
	// Maximum of 5 seconds
	if (rate < 5*1000)
		rate = 5*1000;
	
	return rate;
}
// END LIVE SITE AJAXING


// MISC FUNCTIONS
function centerElement(el)
{
	var w = $(el).width();
	var h = $(el).height();
	var offsetX = (48-w)/2;
	var offsetY = (48-h)/2;
	
	//debug.debug('w='+w+' h='+h+' offsetX='+offsetX+' offsetY'+offsetY);
	
	$(el).css('left', offsetX+'px').css('top', offsetY+'px');
}

function stripNonNumeric( str )
{
  str += '';
  var rgx = /^\d|\.|-$/;
  var out = '';
  for( var i = 0; i < str.length; i++ )
  {
    if( rgx.test( str.charAt(i) ) ){
      if( !( ( str.charAt(i) == '.' && out.indexOf( '.' ) != -1 ) ||
             ( str.charAt(i) == '-' && out.length != 0 ) ) ){
        out += str.charAt(i);
      }
    }
  }
  return out;
}

function addCommas(nStr)
{
  nStr += '';
  x = nStr.split('.');
  x1 = x[0];
  x2 = x.length > 1 ? '.' + x[1] : '';
  var rgx = /(\d+)(\d{3})/;
  while (rgx.test(x1)) {
    x1 = x1.replace(rgx, '$1' + ',' + '$2');
  }
  return x1 + x2;
}
// END MISC FUNCTIONS

