/**
 * @author will
 */

var fv = null;
var actionURL = null;
var formHTML = null;
var formState = 'default'; // 'added';
var badURLs = new Array(); // Get added to this array if found to be bad. Used in validation checks.
var goodURLs = new Array(); 
var checkURLRequestsPending = new Array();
if(!$defined(autoAddPin)){
	var autoAddPin = false;		
}

/**
 * 
 */
window.addEvent('domready', function(){
    
    var responseTest = false;
    if(responseTest){
        
        // Build response object which will look like this:
        responseObj = new Object();
        responseObj.success = true;
        responseObj.pin_url = "http://www.testfromjs.com";
        responseObj.page_title = "Page title. Lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor";
        responseObj.pin_term = "Test term. Lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor";
        responseObj.pin_comment = "Test comment. Lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor lorem ipsum dolor";
        responseObj.pin_code = "12346";
        
        // Also set form fields then validate
        $$('.inpURL')[0].set('value', responseObj.pin_url);
        $$('.inpPin_Term')[0].set('value', responseObj.page_title);
        $$('.inpPin_Comment')[0].set('value', responseObj.pin_comment);
        
        // Show form success
        formShowSuccess(responseObj);
    }

	
	// Store current pin code so can be used to report bad pins etc.
	// Use test for now.
	// $$('body')[0].store('currentPinCode', 'x0gXoC');
	// $$('body')[0].store('currentPinURL', 'http://bbc.co.uk');
	
	// One off setup of validator form
	fv = new FormValidator($$('.fncAddPinForm')[0]);
	actionURL = $$('.fncAddPinForm')[0].get('action');
	
	// Disable standard form button behavior as they will be handled by JS.
	$$('.fncAddPinForm button').addEvent('click', function(ev){
		ev.preventDefault();
	});
	
	$$('button.butPreview')[0].addEvent('click', previewAction);
	$$('button.butShorten')[0].addEvent('click', shortenAction);
	
	// Example custom validator
	fv.add('validatePPURL', {
		errorMsg: 'The URL is not valid.',
		test: function(el){
			
			if(badURLs.contains(el.get('value'))){
				setInputState(el, 'CONFIRMED_INVALID', "Yikes, we can't use that URL.");
				return false;
			}
			
			// Changed so can no longer be considered to be confirmedInvalid.
			// if(el.hasClass('confirmedInvalid')) el.removeClass('confirmedInvalid');
			
			// Test for default
			var defValue = el.retrieve('defValue');
			if(el.get('value') == defValue || el.get('value') == ''){
				setInputState(el, 'NEUTRAL');
				return false;
			}
			
			// Check if is a URL. If it is then supply the tick.
			if(!fv.validators['validate-url'].test(el) || el.get('value').length < 1){
				setInputState(el, 'INVALID');
				return false;
			}
			
			// Apply valid class
			setInputState(el, 'VALID');
			
			return true;
		}	
	});
	
	// Not required but can't be over 255 chars long.
	// Only show valid class if its also not the defaulter copy.
	fv.add('validatePPTerm', {
		errorMsg: 'The pinpoint phrase is not valid.',
		test: function(el){
			
			if(el.value.length > 500){
				setInputState(el, 'INVALID', 'The phrase is too long.');
				return false;
			}
			
			// Show its valid if not trimmed default value.
			var defValue = el.retrieve('defValue');
			if(defValue != el.value && el.value.length > 0){
				setInputState(el, 'VALID');
			} else {
				// Valid as default but to not show the valid class to the user
				setInputState(el, 'NEUTRAL');
			}
		
			return true;
		}	
	});
	
	// Not required but can't be over 255 chars long.
	// Only show valid class if its also not the defaulter copy.
	fv.add('validatePPComment', {
		errorMsg: 'The comment is not valid.',
		test: function(el){
			
			if(el.value.length > 500){
				setInputState(el, 'INVALID', 'The comment is too long.');
				return false;
			}
			
			// TODO: If does not have associated search term then need to make
			// the search term should become invalid.
			
			// Show its valid if not trimmed default value.
			var defValue = el.retrieve('defValue');
			if(defValue != el.value && el.value.length > 0){
				setInputState(el, 'VALID');
				
			} else {
				setInputState(el, 'NEUTRAL');
			}
			return true;
		}	
	});
	
	// Set up events for form validation.
	var allInpElems = $$('.fncAddFormInp');
	addValidationEvents(allInpElems);
	
	// Apply validation on doc load too.
	if(autoAddPin){
		// In case return from twitter
		shortenAction();
	} else {
		validateAddForm();
	}
});


var setInputState = function(el, state, errorMessage)
{
	switch(state){
		case 'VALID':
			el.removeClass('invalid');
			el.removeClass('confirmedInvalid');
			if(!el.hasClass('valid')) el.addClass('valid');
			hideErrorFeedbackForInputElem(el);
		break;
		case 'INVALID':
			el.removeClass('valid');
			el.removeClass('confirmedInvalid');
			if(!el.hasClass('invalid')) el.addClass('invalid');
			if(errorMessage != null){
				showErrorFeedbackForInputElem(el, errorMessage);
			}
		break;
		case 'INVALID_CONFIRMED':
			el.removeClass('valid');
			el.removeClass('invalid');
			if(!el.hasClass('confirmedInvalid')) el.addClass('confirmedInvalid');
			if(errorMessage != null){
				showErrorFeedbackForInputElem(el, errorMessage);
			}
        break;
		case 'NEUTRAL':
			el.removeClass('valid');
			el.removeClass('invalid');
			el.removeClass('confirmedInvalid');
			hideErrorFeedbackForInputElem(el);
		break;
		default:
	}
}

// 
var showErrorFeedbackForInputElem = function(inputElem, message)
{
	// Find parent segment
	var segmentElem = inputElem.getParent('.segment');
	var errorFeedbackElem = new Element('div', {
		'class' : 'errorFeedback'
	});
	
	var wrapElem = new Element('div', {'class' : 'wrap'});
	var messageElem = new Element('h3',{'html' : message});
	var arrowElem = new Element('img', {'src' : '/x/img/red-arrow.png','class':'arrow'});
	var feedbackPara = new Element('p', {'class' : 'feedback', 'html' : ' about it?'});
	var feedbackLink = new Element('a', {'html' : 'Send us some feedback', 'href' : 'mailto:hickups@pinpnt.info?subject=Pin trouble'});
	
	messageElem.inject(wrapElem);
	arrowElem.inject(wrapElem);
	feedbackLink.inject(feedbackPara, 'top');
	feedbackPara.inject(wrapElem, 'bottom');
	
	wrapElem.inject(errorFeedbackElem);
	errorFeedbackElem.inject(segmentElem, 'bottom');
}

var hideErrorFeedbackForInputElem = function(inputElem)
{
	// Find parent segment
	var segmentElem = inputElem.getParent('.segment');
	var errorFeedbackElems = segmentElem.getElements('.errorFeedback');
	errorFeedbackElems.destroy();
}

window.addEvent('domready', function(){
	// Add report failed pin link action
	
    if(!$defined($$('.fncReporterBlock a.fncReportFailed')[0])) return;
    
	// If pin available and link available then fetch.
	$$('.fncReporterBlock a.fncReportFailed')[0].addEvent('click', function(ev){
		
		ev.preventDefault();
		
		// Check can get data
		// TODO: enable this to be stored anywhere e.g. in an element that
		// would also be available in the heading.
		// Could just store pin codes.
		var pinURL = $$('body')[0].retrieve('currentPinURL');
		var pinCode = $$('body')[0].retrieve('currentPinCode');
		
		if(isEmpty(pinCode) || pinCode == null){
			alert('Sorry, we could not report this URL.');
			return;
		}
		
		if(!confirm('Report that "' + pinURL +'" is not working for Pinpoint?')) return;
		
		// OK confirmed so send report
		var req = new Request.JSON({
			url: '/pin/userreportbadurl/',
			onRequest: function(responseObj){},
			onFailure: function(xhr){ alert('Report failed.'); },
			onSuccess: function(responseObj){
				alert(responseObj.user_message);
			}
		});
		req.post({
			'pin_code' : pinCode,
			'pin_url' : pinURL
		});
		
	});
});

var goTwitterAuth = function(){
	if(authURL){
		window.location = authURL;
		return true;
	}
	return false;
}

var shortenAction = function(event){
	
	/**
	 * TODO - if not logged in store these form values to session via a 
	 * a different action, and on call back present pop up confirm message.
	 * 
	 * On confirm then all should need to do is redirect user to twitter sign
	 * in.
	 */
	
	// Ensure form action set to make pi URL
	$$('.fncAddPinForm')[0].set('action', '/pin/add/');
		
	if(!fv.validate()){
		
		formShowErrors();
		
	} else {
		
		//This code will send a data object via a GET request and alert the retrieved data.
		var jsonRequest = new Request.JSON({
			
			url: $$('.fncAddPinForm')[0].get('action'),
			
			onRequest: function(responseObj){
				// Show loading until get fail or success
				formShowLoading();
			},
			
			onFailure: function(xhr){ // xhr - (XMLHttpRequest) The transport instance.
				formShowRestore();
				alert('Failed to make link');
			},
			
			// Not this is just onSuccess of the actuion JSON call. Not
			// necessarily success of the user interaction.
			onSuccess: function(responseObj){
				
				// console.log(responseObj, 'Response Object');
				
				if(!responseObj.success){
					
					// Check if failed because user is not logged in?
					if(responseObj.fail_code == 'USER_NOT_LOGGED_IN'){
						
						authURL = responseObj.last_auth_url;
						if(authURL == null){
							
							// No URL to authenticate user with
							alert("Yikes! Something went wrong!");
							
						} else {
						
							// Show message saying redirecting to twitter
							var toTwitterWrapElem = new Element('div',{
								'class' : 'messageBoxSmall addFormOverlay',
								'html' : '<h3>We\'re going to redirect you to Twitter to login.</h3><p>See you in a second...</p>'
							});
							
							if($$('.loadingContainer')[0]) $$('.loadingContainer')[0].destroy();
							toTwitterWrapElem.inject($$('.fncAddPinFormContainer')[0], 'top');
							var authTimer = goTwitterAuth.delay(3000);
						}
						
					} else {
					
						// TODO nice fail response.
						alert("Yikes! Something went wrong! We could not make this Pin.");
						formShowRestore();
					}
					
				} else {
					
					// Copy URL to clipboard
					var clip = new ZeroClipboard.Client();
					clip.glue($$('.clipHolder')[0]);
					
					//Add a complete event to let the user know the text was copied
				    clip.addEventListener('complete', function(client, text) {
				        alert("Copied text to clipboard:\n" + text);
				    });
					
					clip.addEventListener('load', function(client) {
				        // alert("Loaded clipboard client");
						// console.log(client, "client");
				    });
					
					clip.addEventListener('error', function(client) {
				        // alert("Error");
				    });
					
					
				    clip.setText(responseObj.pin_url);
					
					// Show form success.
					formShowSuccess(responseObj);
					// TODO also show new most recent links
					
				}
				
			}
		});
		
		// Ensure data is not default value (should not be posted)
		var pinTermVal = hasDefaultOrEmptyValue($('pin_term')) ? '' : $('pin_term').get('value');
		var pinCommentVal = hasDefaultOrEmptyValue($('pin_comment'))  ? '' : $('pin_comment').get('value');
		var urlVal = hasDefaultOrEmptyValue($('url'))  ? '' : $('url').get('value');

		jsonRequest.post({
			'url': urlVal,
			'pin_term': pinTermVal,
			'pin_comment': pinCommentVal
		});
		
	}
}


var previewAction = function(event){
	
	if(!fv.validate()){
	
		// alert('TODO: preview invalid action - show some validation feedback');
		formShowErrors();
	
	} else {
		
		var allInpElems = $$('.fncAddFormInp');
		
		// removeValidationEvents(allInpElems);
		
		// TODO: test can connect to URL here.
		var formNameElem = new Element('input', {
			type: 'hidden',
			name: 'form_name',
			value: 'preview',
			id: 'add_pin_form_name'
		});
		
		$$('.fncAddPinForm')[0].set('target', '_blank');
		$$('.fncAddPinForm')[0].set('action', '/preview/');

		formNameElem.inject($$('.fncAddPinForm')[0], 'top');
		
		$$('.fncAddPinForm')[0].submit();
	}
}

function formShowLoading(){
	
	var ldElemContainer = new Element('div', {'class':'loadingContainer'});
	var ldElemH3 = new Element('h3', {'html':'Making the short link...'});
	var ldElemImg = new Element('img', {'src':'/x/img/loading-circle.gif'});
	
	// Build it.
	ldElemH3.inject(ldElemContainer);
	ldElemImg.inject(ldElemContainer, 'bottom');
	
	// Hide the form.
	$$('.fncAddPinForm')[0].setStyles({
		display: 'none'
	});
	
	ldElemContainer.inject($$('.fncAddPinForm')[0], 'after');
}

/* This just handles from restore from hidden state rather than the butchered
  showSuccess state. */
function formShowRestore(){
	if($$('.loadingContainer')[0]){
		// destroy
		$$('.loadingContainer')[0].dispose();
	}
	$$('.fncAddPinForm')[0].setStyles({
		display: 'block'
	});
}

function formShowSuccess(responseObj){
    
    // alert('show form success called');
	
	// Fade out and destroy.
	if ($$('.loadingContainer')[0]){
        $$('.loadingContainer')[0].dispose();
    }
	
    // Page title
    var pageTitle = '';
    var pinTerm = '';
    var pinComment = '';
    
    var maxPageTitle = 50;
    var maxPinTerm = 50;
    var maxPinComment = 50;
    
    if(responseObj.page_title){
        pageTitle = responseObj.page_title.length > maxPageTitle ? responseObj.page_title.substring(0, maxPageTitle) + '...' : responseObj.page_title;
    }
    
    if(responseObj.pin_term){
        pinTerm = responseObj.pin_term.length > maxPinTerm ? responseObj.pin_term.substring(0, maxPinTerm) + '...' : responseObj.pin_term;
    }
    
    if(responseObj.pin_comment){
        pinComment = responseObj.pin_comment.length > maxPinComment ? responseObj.pin_comment.substring(0, maxPinComment) + '...' : responseObj.pin_comment;
    }
    
    // Hide existing input fields (not buttons)
    $$('.fncInputFields')[0].setStyle('display', 'none');
    $$('.homePinForm')[0].removeClass('fixedHeight');
    
    
    var inpFields = $$('.fncAddPinForm .fncAddFormInp');
    var topHTML = '<h3>We shortened your link to <a target="_blank" href="' +
        responseObj.pin_url +
        '">' + 
        responseObj.pin_url + 
        '</a></h3><p>Click the Preview button to see how it looks.</p>';
        
        
    var botHTML = '<p>You can retrieve this from <a target="_blank" href="/links/">My Links</a></p>';
    botHTML += '<p class="details">';
    
    if(pageTitle) botHTML += '<span>Page</span> ' + pageTitle + '<br/>';
    if(pinTerm) botHTML += '<span>Link</span> ' + pinTerm + '<br/>';
    if(pinComment) botHTML += '<span>Comment</span> ' + pinComment + '<br/>';
    botHTML += '</p>';
    
    // 
    var topSuccessContElem = new Element('div', {
        'class' : 'successContainerTop',
        'html' : topHTML
    });
    
    var botSuccessContElem = new Element('div', {
        'class' : 'successContainerBot',
        'html' : botHTML
    });
    
    topSuccessContElem.inject($$('.fncAddPinForm')[0], 'top');
    botSuccessContElem.inject($$('.fncAddPinForm')[0], 'bottom');
    $$('.fncAddPinForm')[0].setStyle('display', 'block');
    
    // DEAL WITH SHORTEN BUTTON
    // Turn shorten button into shorten another link and add behavior to it
    var shortenButton = $$('.homePinForm .butShorten')[0];
    var previewButton = $$('.homePinForm .butPreview')[0];
    
    // Ensure preview button enabled.
    previewButton.removeClass('stateOff');
    if(!previewButton.hasClass('stateOn')) previewButton.addClass('stateOn');
    
    shortenButton.removeClass('stateFirst');
    shortenButton.addClass('stateAnother');
    shortenButton.removeEvents();
    shortenButton.addEvent('click', function(ev){
        ev.preventDefault();
        if(confirm('Do really want to shorten another link?')){
                        
            // So re-enstate the form to its initial state.
            addValidationEvents(inpFields);
            
            // Get classes back to default state.
            for (var i = 0; i < inpFields.length; i++) {
                inpFields[i].removeClass('readonly');
                inpFields[i].removeClass('inserted');
                inpFields[i].removeClass('valid');
                inpFields[i].removeClass('invalid');
                inpFields[i].setStyle('display', 'block');
                inpFields[i].set('value', inpFields[i].retrieve('defValue'));
            }
           
            // Remove feedback bits
            $$('.successContainerTop')[0].destroy();
            $$('.successContainerBot')[0].destroy();
            
            // Restore submit event.
            shortenButton.removeEvents();
            shortenButton.addEvent('click', function(ev){ev.preventDefault();});
            shortenButton.addEvent('click', shortenAction);
            shortenButton.removeClass('stateAnother');
            shortenButton.addClass('stateFirst');
       
            // Show 
            $$('.fncInputFields')[0].setStyle('display', 'block');
            $$('.homePinForm')[0].addClass('fixedHeight');
            
            //
            previewButton.removeClass('stateOn');
            if(!previewButton.hasClass('stateOff')) previewButton.addClass('stateOff');
        }
    });
    
    return;
}

// Ideally this would shopw tooltips over each specific form field.
function formShowErrors(){
	
	// alert('Show form errors called');
	
	var outputStr = "";
	var heading = "Error shortening link"
	var bodyStr = "";
	
	// Have to do this explicitly for not as validation class does not seem to
	// provide the API for this.
	if(!fv.validateField($$('.inpURL')[0])){
		bodyStr += "\nThe URL is not valid.";
	}
	
	outputStr += heading + "\n";
	outputStr += bodyStr;
	
	alert(outputStr);
}


function isEmpty(str){
	return str.replace(/^\s+|\s+$/, '') == '';
}



function hasDefaultOrEmptyValue(el){
	var defVal = el.retrieve('defValue');
	if(el.get('value') == defVal) return true;
	if(isEmpty(el.get('value'))) return true;
	return false;
}


function addValidationEvents(allInpElems){
	
	// Ensure validation is on.
	fv.start();
	
	// [TODO: these defaulters should be generated by PHP's addFormDefaultParams array]
	addDefaulterField('input.fncInpDefaulter.inpURL', 'Your link');
	addDefaulterField('input.fncInpDefaulter.inpPin_Term', 'Paste a phrase to pinpoint - optional');
	addDefaulterField('textarea.fncInpDefaulter.inpPin_Comment', 'Add a comment - optional');
	
	// 
	allInpElems.addEvents({
		'keyup': function(){
			validateAddForm();
		},
		'change': function(){
			validateAddForm();
		},
		'blur': function(){
			validateAddForm();
		},
		'focus': function(){
			validateAddForm();
		}
	});
	
	var inpURL = $$('input.inpURL')[0];
	
	// Append http:// if no http protocol supplied.
	inpURL.addEvent('change', function(){fixURLRequest(inpURL)});
	inpURL.addEvent('blur', function(){fixURLRequest(inpURL)});
}

/**
 * JSON call to fix URL and corrects URL field appropriately.
 */
function fixURLRequest(inpURL){
    
    var url = inpURL.get('value');
    
    // Make sure no duplicate requests
    if(checkURLRequestsPending.contains(url)){
        return;
    }
	
	if(badURLs.contains(url)){
		setInputState(inpURL, 'INVALID_CONFIRMED', "Yikes, we can't use that link.");
		return;
	}
    
    if(goodURLs.contains(url)){
        setInputState(inpURL, 'VALID');
        return;
    }
	
	// Check if default value or empty so then don't bother appending with https
	var defVal = inpURL.retrieve('defValue');
	if(inpURL.get('value') == defVal || isEmpty(inpURL.get('value'))){
		return;
	} 

	if(!inpURL.get('value').match(/^http:\/\/|^https:\/\//)){
		inpURL.set('value', 'http://' + inpURL.get('value'));
	}
	// Now, with the amended URL perform the JSON test to get beck
	// either a corrected URL or just feedback that it is duff.
	var req = new Request.JSON({
		url: '/pin/urlfix/',
		onRequest: function(responseObj){
            
            // Flag that this URL is being checked.
            checkURLRequestsPending.push(inpURL.get('value'));
            
        },
		onFailure: function(xhr){},
		onSuccess: function(responseObj){
            
            checkURLRequestsPending.erase(responseObj.origURL);
            
			if(responseObj.success){
				
				// Just set the fixed URL to be the one to use for now.
				// on a 302 we could just ask with a JS prompt if its cool.
                goodURLs.push(responseObj.useURL);
				inpURL.set('value', responseObj.useURL);
				setInputState(inpURL, 'VALID');
				
			} else {
				
				// TODO The URL is invalid to use for pinpointer so add it to
				// the bad list to check against and add confirmedInvalid
				if(!inpURL.hasClass('confirmedInvalid')){
					inpURL.addClass('confirmedInvalid');
					
					setInputState(inpURL, 'INVALID_CONFIRMED', "Yikes, we can't use that URL.");
					
					// Put the duff URLs to th  bas list so no need to check on 'em again.
					badURLs.push(responseObj.useURL);
					badURLs.push(responseObj.origURL);
				}
			}
		}
	});
	req.post({'url' : inpURL.get('value')});
}


function removeValidationEvents(allInpElems){
    
    // Prevent validation.
    if(fv) fv.stop();
    
	// Prevent realtime events.
	allInpElems.removeEvents();
}

function validateAddForm()
{
	
	var previewButEl = $$('button.butPreview')[0];
	var shortenButEl = $$('button.butSorten')[0];
	
	if(fv.validate()){
		
		// Update UI.
		if(!previewButEl.hasClass('stateOn')) previewButEl.addClass('stateOn');
		if(previewButEl.hasClass('stateOff')) previewButEl.removeClass('stateOff');
		
		// [Button action are handled internally with formIsValid]
	
	} else {
	
		if(!previewButEl.hasClass('stateOff')) previewButEl.addClass('stateOff');
		if(previewButEl.hasClass('stateOn')) previewButEl.removeClass('stateOn');
		
		// [Button action are handled internally with formIsValid] 
		
	}
}
