/*
 * Copyright 2017 Coveros, Inc.
 * 
 * This file is part of Selenified.
 * 
 * Selenified is licensed under the Apache License, Version
 * 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy 
 * of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, 
 * software distributed under the License is distributed on 
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
 * KIND, either express or implied. See the License for the 
 * specific language governing permissions and limitations 
 * under the License.
 */

package com.coveros.selenified.selenium;

import java.util.List;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import com.coveros.selenified.exceptions.InvalidLocatorTypeException;
import com.coveros.selenified.selenium.Selenium.Locator;

public class Element {

    private Locator type;
    private String locator;
    private int match = 0;

    private WebDriver driver;

    public Element(Locator type, String locator) {
        this.setType(type);
        this.setLocator(locator);
    }

    public Element(Locator type, String locator, int match) {
        this.setType(type);
        this.setLocator(locator);
        this.setMatch(match);
    }

    public void setType(Locator type) {
        this.type = type;
    }

    public void setLocator(String locator) {
        this.locator = locator;
    }

    public void setMatch(int match) {
        this.match = match;
    }

    public void setDriver(WebDriver driver) {
        this.driver = driver;
    }

    public Locator getType() {
        return type;
    }

    public String getLocator() {
        return locator;
    }

    public int getMatch() {
        return match;
    }

    public WebDriver getDriver() {
        return driver;
    }

    /**
     * A nice output to identify the element by locator and selector
     * 
     * @return String: text identifying how the element was located
     */
    public String prettyOutputStart() {
        return "Element with <i>" + type.toString() + "</i> of <i>" + locator + "</i>";
    }

    /**
     * A nice output to identify the element by locator and selector
     * 
     * @return String: text identifying how the element was located
     */
    public String prettyOutputLowercase() {
        String output = prettyOutputStart();
        return Character.toLowerCase(output.charAt(0)) + output.substring(1);
    }

    /**
     * A nice output to identify the element by locator and selector
     * 
     * @return String: text identifying how the element was located
     */
    public String prettyOutput() {
        return " " + prettyOutputLowercase() + " ";
    }

    /**
     * A nice output to identify the element by locator and selector
     * 
     * @return String: text identifying how the element was located
     */
    public String prettyOutputEnd() {
        return prettyOutputLowercase() + ".";
    }

    //////////////////////////////////////////////////////
    // setup element values
    //////////////////////////////////////////////////////

    /**
     * a method to determine selenium's By object using selenium webdriver
     *
     * @return By: the selenium object
     * @throws InvalidLocatorTypeException
     */
    private By defineByElement() {
        // consider adding strengthening
        By byElement = By.id("");;
        switch (type) { // determine which locator type we are interested in
        case XPATH:
            byElement = By.xpath(locator);
            break;
        case ID:
            byElement = By.id(locator);
            break;
        case NAME:
            byElement = By.name(locator);
            break;
        case CLASSNAME:
            byElement = By.className(locator);
            break;
        case CSS:
            byElement = By.cssSelector(locator);
            break;
        case LINKTEXT:
            byElement = By.linkText(locator);
            break;
        case PARTIALLINKTEXT:
            byElement = By.partialLinkText(locator);
            break;
        case TAGNAME:
            byElement = By.tagName(locator);
            break;
        }
        return byElement;
    }

    /**
     * a method to grab the identified matching web element using selenium
     * webdriver
     *
     * @return WebElement: the element object, and all associated values with it
     * @throws InvalidLocatorTypeException
     */
    public WebElement getWebElement() {
        List<WebElement> elements = getWebElements();
        if (elements.size() > match) {
            return elements.get(match);
        }
        return driver.findElement(defineByElement());
    }

    /**
     * a method to grab all matching web elements using selenium webdriver
     *
     * @return List<WebElement>: a list of element objects, and all associated
     *         values with them
     * @throws InvalidLocatorTypeException
     */
    public List<WebElement> getWebElements() {
        return driver.findElements(defineByElement());
    }
}
@@ -698,16 +698,44 @@
 enium;%0A%0A
+import java.util.ArrayList;%0A
 import j
@@ -857,16 +857,53 @@
 Element;
+%0Aimport org.testng.log4testng.Logger;
 %0A%0Aimport
@@ -1027,32 +1027,153 @@
 or;%0A
-%0Apublic class Element %7B%0A
+import com.coveros.selenified.tools.General;%0A%0Apublic class Element %7B%0A%0A    private static final Logger log = Logger.getLogger(General.class);%0A    
 %0A   
@@ -3610,32 +3610,67 @@
 efineByElement()
+ throws InvalidLocatorTypeException
  %7B%0A        // co
@@ -3721,21 +3721,8 @@
 ment
- = By.id(%22%22);
 ;%0A  
@@ -4478,32 +4478,102 @@
          break;%0A
+        default:%0A            throw new InvalidLocatorTypeException();%0A
         %7D%0A      
@@ -5013,32 +5013,50 @@
 tch);%0A        %7D%0A
+        try %7B%0A    
         return d
@@ -5089,24 +5089,135 @@
 Element());%0A
+        %7D catch (InvalidLocatorTypeException e) %7B%0A            log.error(e);%0A            return null;%0A        %7D%0A
     %7D%0A%0A    /
@@ -5506,24 +5506,42 @@
 lements() %7B%0A
+        try %7B%0A    
         retu
@@ -5579,19 +5579,143 @@
 Element());%0A
+        %7D catch (InvalidLocatorTypeException e) %7B%0A            log.error(e);%0A            return new ArrayList%3C%3E();%0A        %7D%0A
     %7D%0A%7D

implement changes for best practices