package com.github.johanbrorson.uimapper;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.openqa.selenium.By;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.github.johanbrorson.uimapper.exceptions.IllegalMethodException;

@JsonPropertyOrder({"name", "selector", "method"})
public class Locator {

  @JsonProperty("name")
  private String name;
  @JsonProperty("selector")
  private String selector;
  @JsonProperty("method")
  private Method method;
  private final Map<String, Object> additionalProperties = new HashMap<String, Object>();

  public enum Method {
    CLASS_NAME, CSS_SELECTOR, ID, LINK_TEXT, NAME, PARTIAL_LINK_TEXT, TAG_NAME, XPATH
  }

  @JsonProperty("name")
  public String getName() {
    return name;
  }

  @JsonProperty("name")
  public void setName(String name) {
    this.name = name;
  }

  @JsonProperty("selector")
  public String getSelector() {
    return selector;
  }

  @JsonProperty("selector")
  public void setSelector(String selector) {
    this.selector = selector;
  }

  @JsonProperty("method")
  public Method getMethod() {
    return method;
  }

  @JsonProperty("method")
  public void setMethod(Method method) {
    this.method = method;
  }

  @JsonAnyGetter
  public Map<String, Object> getAdditionalProperties() {
    return this.additionalProperties;
  }

  @JsonAnySetter
  public void setAdditionalProperty(String name, Object value) {
    this.additionalProperties.put(name, value);
  }

  public By getBy() throws IllegalMethodException {
    switch (method) {
      case CLASS_NAME:
        return By.className(selector);
      case CSS_SELECTOR:
        return By.cssSelector(selector);
      case ID:
        return By.id(selector);
      case LINK_TEXT:
        return By.linkText(selector);
      case NAME:
        return By.name(selector);
      case PARTIAL_LINK_TEXT:
        return By.partialLinkText(selector);
      case TAG_NAME:
        return By.tagName(selector);
      case XPATH:
        return By.xpath(selector);
      default:
        throw new IllegalMethodException();
    }
  }

  /**
   * Checks if the selector is valid
   *
   * @return <code>true</code> if the selector is valid, otherwise <code>false</code>
   */
  public boolean hasValidSelector() {
    if (selector == null || selector.isEmpty()) {
      return false;
    }

    switch (method) {
      case ID:
        Pattern pattern = Pattern.compile("\\s");
        Matcher matcher = pattern.matcher(selector);
        return !matcher.find();
      case XPATH:
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        try {
          xpath.compile(selector);
        } catch (XPathExpressionException e) {
          return false;
        }
        return true;
      default:
        return true;
    }
  }

}

@@ -2618,80 +2618,198 @@
     
-if (selector == null %7C%7C selector.isEmpty()) %7B%0A      return false
+switch (method) %7B%0A      case ID:%0A        return hasValidIdSelector();%0A      case XPATH:%0A        return hasValidXpathSelector();%0A      default:%0A        return !isSelectorNullOrEmpty()
 ;%0A    %7D%0A
 %0A   
@@ -2808,54 +2808,96 @@
   %7D%0A
-%0A
   
-  switch (method) %7B%0A      case ID:%0A 
+%7D%0A%0A  private boolean hasValidIdSelector() %7B%0A    if (!isSelectorNullOrEmpty()) %7B%0A
       
- 
 Patt
@@ -2934,18 +2934,16 @@
 %22%5C%5Cs%22);%0A
-  
       Ma
@@ -2987,26 +2987,24 @@
 tor);%0A      
- 
- 
 return !matc
@@ -3019,32 +3019,136 @@
 ();%0A    
-  case XPATH:%0A  
+%7D else %7B%0A      return false;%0A    %7D%0A  %7D%0A%0A  private boolean hasValidXpathSelector() %7B%0A    if (!isSelectorNullOrEmpty()) %7B%0A
       XP
@@ -3198,26 +3198,24 @@
 ce();%0A      
- 
- 
 XPath xpath 
@@ -3242,18 +3242,16 @@
 ;%0A      
-  
 try %7B%0A  
@@ -3256,18 +3256,16 @@
         
- 
- 
 xpath.co
@@ -3277,26 +3277,24 @@
 (selector);%0A
-  
       %7D catc
@@ -3330,26 +3330,24 @@
 ) %7B%0A        
-  
 return false
@@ -3348,18 +3348,16 @@
  false;%0A
-  
       %7D%0A
@@ -3358,26 +3358,24 @@
     %7D%0A      
-  
 return true;
@@ -3383,45 +3383,142 @@
     
-  default:%0A        return true;%0A    %7D
+%7D else %7B%0A      return false;%0A    %7D%0A  %7D%0A%0A  private boolean isSelectorNullOrEmpty() %7B%0A    return selector == null %7C%7C selector.isEmpty();
 %0A  %7D

Make hasValidSelector easier to read