# -*- coding: utf-8 -*-

# Licensed under the Open Software License ("OSL") v. 3.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.opensource.org/licenses/osl-3.0.php

# 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.

import os
import sys
import time
import urllib2

from selenium import *
from browser_driver import *
from selenium_element_selector import SeleniumElementSelector

class SeleniumBrowserDriver(BrowserDriver):
    def __init__(self, browser_to_run, tests_dir, extra_args):
        super(type(self),self).__init__(browser_to_run, tests_dir)
        if extra_args.has_key("selenium.server"):
            self.__host__ = extra_args["selenium.server"]
        else:
            self.__host__ = "localhost"
        if extra_args.has_key("selenium.port"):
            self.__port__ = int(extra_args["selenium.port"])
        else:
            self.__port__ = 4444

    def resolve_element_key(self, context, element_type, element_key):
        if context == None: return element_key

        return SeleniumElementSelector.element(element_type, element_key)

    def start_test(self, url = "http://localhost"):
        self.selenium = selenium(self.__host__, self.__port__, self.__browser__, url)
        try:
            self.selenium.start()
        except Exception, e:
            sys.stderr.write("Error when starting selenium. Is it running ? Error: %s\n" % unicode(e))
            sys.exit(1)

    def page_open(self, url):
        self.selenium.open(url)

    def type(self, input_selector, text):
        self.selenium.type(input_selector, text)

    def clean_input(self, input_selector):
        self.selenium.type(input_selector, "")

    def click_element(self, element_selector):
        self.selenium.click(element_selector)

    def is_element_visible(self, element_selector):
        error_message = "ERROR: Element %s not found" % (element_selector)
        is_present = self.selenium.is_element_present(element_selector)
        if is_present:
            try:
                is_present = self.selenium.is_visible(element_selector)
            except Exception, error:
                if error.message == error_message:
                    is_present = False
                else:
                    raise
        return is_present

    def wait_for_page(self, timeout=10000):
        self.selenium.wait_for_page_to_load(timeout)

    def get_title(self):
        return self.selenium.get_title()

    def get_xpath_count(self, xpath):
        return self.selenium.get_xpath_count(xpath)

    def get_class(self, name):
        klass = self.__get_attribute_value(name, 'class')
        return klass

    def is_element_enabled(self, element):
        script = """this.page().findElement("%s").disabled;"""

        script_return = self.selenium.get_eval(script % element)
        if script_return == "null":
            is_disabled = self.__get_attribute_value(element, "disabled")
        else:
            is_disabled = script_return[0].upper()=="T" # is it 'True'?
        return not is_disabled

    def checkbox_is_checked(self, checkbox_selector):
        return self.selenium.is_checked(checkbox_selector)

    def checkbox_check(self, checkbox_selector):
        self.selenium.check(checkbox_selector)

    def checkbox_uncheck(self, checkbox_selector):
        self.selenium.uncheck(checkbox_selector)

    def get_selected_index(self, element_selector):
        return int(self.selenium.get_selected_index(element_selector))

    def get_selected_value(self, element_selector):
        return self.selenium.get_selected_value(element_selector)

    def get_selected_text(self, element_selector):
        return self.selenium.get_selected_label(element_selector)

    def get_element_text(self, element_selector):
        text = ""
        tag_name_script = """this.page().findElement("%s").tagName;"""
        tag_name = self.selenium.get_eval(tag_name_script % element_selector).lower()

        properties = {
                        "input" : "value",
                        "textarea" : "value",
                        "div" : "innerHTML"
                     }

        script = """this.page().findElement("%s").%s;"""
        try:
            # if the element is not in the dict above, I'll assume that we need to use "innerHTML"
            script_return = self.selenium.get_eval(script % (element_selector, properties.get(tag_name, "innerHTML")))
        except KeyError, err:
            raise ValueError("The tag for element selector %s is %s and Pyccuracy only supports the following tags: %s",
                             (element_selector, tag_name, ", ".join(properties.keys)))

        if script_return != "null":
            text = script_return

        return text

    def get_element_markup(self, element_selector):
        script = """this.page().findElement("%s").innerHTML;"""
        script_return = self.selenium.get_eval(script % element_selector)
        return script_return != "null" and script_return or ""

    def get_html_source(self):
        return self.selenium.get_html_source()

    def select_option_by_index(self, element_selector, index):
        return self.__select_option(element_selector, "index", index)

    def select_option_by_value(self, element_selector, value):
        return self.__select_option(element_selector, "value", value)

    def select_option_by_text(self, element_selector, text):
        return self.__select_option(element_selector, "label", text)

    def __select_option(self, element_selector, option_selector, option_value):
        error_message = "Option with %s '%s' not found" % (option_selector, option_value)
        try:
            self.selenium.select(element_selector, "%s=%s" % (option_selector, option_value))
        except Exception, error:
            if error.message == error_message:
                return False
            else:
                raise
        return True

    def get_link_href(self, link_selector):
        return self.__get_attribute_value(link_selector, "href")

    def get_image_src(self, image_selector):
        return self.__get_attribute_value(image_selector, "src")

    def get_link_text(self, link_selector):
        return self.selenium.get_text(link_selector)

    def mouseover_element(self, element_selector):
        self.selenium.mouse_over(element_selector)

    def mouseout_element(self, element_selector):
        self.selenium.mouse_out(element_selector)

    def is_element_empty(self, element_selector):
        current_text = self.get_element_text(element_selector)
        return current_text == ""

    def wait_for_element_present(self, element_selector, timeout):
        elapsed = 0
        interval = 0.5

        while (elapsed < timeout):
            elapsed += interval
            if self.is_element_visible(element_selector):
                return True
            time.sleep(interval)

        return False

    def wait_for_element_to_disappear(self, element_selector, timeout):
        elapsed = 0
        interval = 0.5

        while (elapsed < timeout):
            elapsed += interval
            if not self.is_element_visible(element_selector):
                return True
            time.sleep(interval)

        return False

    def drag_element(self, from_element_selector, to_element_selector):
        self.selenium.drag_and_drop_to_object(from_element_selector, to_element_selector)

    def stop_test(self):
        self.selenium.stop()

    def __get_attribute_value(self, element, attribute):
        try:
            locator = element + "/@" + attribute
            attr_value = self.selenium.get_attribute(locator)
        except Exception, inst:
            if "Could not find element attribute" in str(inst):
                attr_value = None
            else:
                raise
        return attr_value

