/*
 * #%L
 * Stevia QA Framework - Core
 * %%
 * Copyright (C) 2013 - 2014 Persado Intellectual Property Limited
 * %%
 * Copyright (c) Persado Intellectual Property Limited. All rights reserved.
 *  
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *  
 * * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *  
 * * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *  
 * * Neither the name of the Persado Intellectual Property Limited nor the names
 * of its contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *  
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * #L%
 */
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;

import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.select.Elements;

import us.codecraft.xsoup.Xsoup;
import us.codecraft.xsoup.xevaluator.XElements;


public class SelectorFetcher {

	
	public static void main(String args[]) throws MalformedURLException, IOException {
		
		//Connection connect = Jsoup.connect("https://www.edline.net/InterstitialLogin.page");
		//Connection connect = Jsoup.connect("http://stgweb01.ath.persado.com:8080/mcs-management-web/login");
		Connection connect = Jsoup.connect("http://woot.com");
		connect.followRedirects(true);
		connect.userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:29.0) Gecko/20100101 Firefox/29.0");
		connect.timeout(60000);
		//TODO add cookies
		//TODO add headers
		
		
		Document doc = connect.get();
		//System.out.println(doc.outerHtml());
		
		

		for (Element e : doc.getAllElements()) {
			if (e.tagName().contains("root")) continue; //skip the html element!
			if (e.tag().isFormSubmittable() || e.tag().getName().equals("a") || e.tag().getName().equals("button")) {
				//System.out.println("---> "+e);
				if ( e.tag().isFormSubmittable() ) {
					String loc = e.nodeName();
					if (e.parent() != null) {
						loc = e.parent().nodeName() + " > " + e.nodeName();
					}
					if (e.hasAttr("id")) {
						try {
							//System.out.println("CSS3: "+verifyLocator(e,loc+"#"+e.attr("id")));
							verifyLocator(e,loc+"#"+e.attr("id"));
						} catch (Exception e1) {
							System.out.println("CSS3: cannot get locator for "+e+"! not verifiable, cause = "+e1.getMessage());
						}
					} else if (e.hasAttr("name")) {
						try {
							//System.out.println("CSS3: "+verifyLocator(e,loc+"[name="+e.attr("name")+"]"));
							verifyLocator(e,loc+"[name="+e.attr("name")+"]");
						} catch (Exception e1) {
							System.out.println("CSS3: cannot get locator for "+e+"! not verifiable, cause = "+e1.getMessage());
						}
					}
				}
				computeRecursiveXpath(e);

			}
		}
		
		
		System.out.println("\n\nLocators found (unique only!)");
		for (Node node : uniqueLocators.keySet()) {
			System.out.println("----------------------------");
			System.out.println("HTML Element: "+node);
			System.out.println("Locator: "+uniqueLocators.get(node));
		}
		
	}

	static Map<Node, String> uniqueLocators = new HashMap<Node, String>();
	
	
	/**
	 * verify an element locator as unique
	 * @param e
	 * @param locator
	 * @return
	 * @throws Exception 
	 */
	private static String verifyLocator( Element e, String locator) throws Exception {
		Element rootElement = e.parents().last();
		if(!locator.startsWith("//")) {
			Elements selected = rootElement.select(locator);
			if (selected.size() == 1) {
				if (!uniqueLocators.containsKey(e)) {
					uniqueLocators.put(e, locator);
				}
				return locator + " UNIQUE = "+selected.first();
			} else if (selected.size() > 1) {
				return locator + " NON-UNIQUE = "+selected;
			} else {
				return locator +" NOT FOUND - PROBLEM";
			}
		} else if(locator.startsWith("//")) { //xpath 
		    XElements elements = Xsoup.select(rootElement, locator);
		    if (elements.getElements().size() > 1) {
		    	return locator + " NON-UNIQUE!!! ";
		    } else if (elements.getElements().size() == 0) {
		    	return locator +" NOT FOUND - PROBLEM";
		    }
		    if (!uniqueLocators.containsKey(e)) {
				uniqueLocators.put(e, locator);
			}
		    return locator + " UNIQUE = "+ elements.getElements().get(0);
		    
		}
		
		return locator + " XPATH?";
	}

	private static void computeRecursiveXpath( Element e) {
		try {
			if (e.hasAttr("id")) {
				String xpath = "//"+reversePath(e)+"[@id='"+e.attr("id")+"']";
				//System.out.println("XPATH: "+verifyLocator(e,xpath));
				verifyLocator(e,xpath);
			}

			if (e.hasAttr("name")) {
				String xpath = "//"+reversePath(e)+"[@name='"+e.attr("name")+"']";
				//System.out.println("XPATH: "+verifyLocator(e,xpath));
				verifyLocator(e,xpath);
			}

			if (e.hasAttr("class") && e.attr("class").length() > 0){
				String xpath = "//"+reversePath(e)+"[@class='"+e.attr("class")+"']";
				//System.out.println("XPATH: "+verifyLocator(e,xpath));				
				verifyLocator(e,xpath);

			}

			if (e.hasAttr("href") && !e.attr("href").equals("#")) {
				String xpath = "//"+reversePath(e)+"[@href='"+e.attr("href")+"']";
				//System.out.println("XPATH: "+verifyLocator(e,xpath));			
				verifyLocator(e,xpath);
			} 
		}catch (Exception ex) { // try a less dangerous xpath
			String locator = "";
			
			locator = "//"+reversePath(e);
			try {
				//System.out.println("XPATH: "+verifyLocator(e,locator));			
				verifyLocator(e,locator);
			} catch (Exception e1) { // failed totally
				System.out.println("cannot detect locator for "+e.tagName()+" cause = "+e1.getMessage());
			}
			
		}
	}

	private static String reversePath(Element e) {
		String loc = e.tagName();
		int div = 0;
		while (e.parent()!=null) {
			String tag = e.parent().tagName().toLowerCase();
			if (tag.compareTo("body")==0) {
				break;
			} else {
				loc = tag + "/" + loc;
			}
			
			if (tag.contentEquals("div")) {
				div++;
				if (div == 2) {
					break;
				}
			} else if (tag.contentEquals("form")) {
				break;
			}
			
			e = e.parent();
		}
		return loc;
	}
}