# w.c.s. - web application for online forms
# Copyright (C) 2005-2013  Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.

import os
import time
import urllib2
import subprocess
import shutil
import signal
import sys

WCS_SRCDIR = '../../'
WCSCTL = '../../wcsctl.py'
WCS_DATA_DIR = os.path.abspath('../../data')

from robot.libraries.BuiltIn import BuiltIn

from Selenium2Library.locators import ElementFinder as BaseElementFinder
from Selenium2Library import utils

class ElementFinder(BaseElementFinder):
    def __init__(self):
        BaseElementFinder.__init__(self)
        self._strategies['qx'] = self._find_by_qx_field

    def _find_by_qx_field(self, browser, criteria, tag, constraints):
        xpath_value = utils.escape_xpath_value(criteria)
        criterias = [
                "//div[div[@class='title'][text()=%s]]/div[@class='content']/input" % xpath_value,
                "//div[div[@class='title'][text()=%s]]/div[@class='content']/select" % xpath_value,
                "//div[div[@class='title'][text()=%s]]/div[@class='content']/textarea" % xpath_value,
                "//div/div[@class='content']//label[text()=%s]/input[@type='checkbox']" % xpath_value]
        for criteria in criterias:
            if browser.find_elements_by_xpath(criteria):
                return self._find_by_xpath(browser, criteria, tag, constraints)
        return []

class WcsRobotFrameworkLibrary:
    def __init__(self, port=10003):
        self.port = port
        try:
            seleniumlib = BuiltIn().get_library_instance('Selenium2Library')
        except RuntimeError:
            # the selenium library has not yet been loaded, monkeypatch it from
            # the outside
            import Selenium2Library.locators.elementfinder
            import Selenium2Library.keywords._element
            Selenium2Library.locators.elementfinder.ElementFinder = ElementFinder
            Selenium2Library.keywords._element.ElementFinder = ElementFinder
        else:
            # the selenium library is already loaded, and the ElementFinder
            # will therefore already have been instantiated, replace it.
            seleniumlib._element_finder = ElementFinder()

    def _waitforport(self, start):
        while True:
            if time.time() - start > 90:
                raise Exception('Servers did not start in 90 seconds!!')
            time.sleep(1)
            try:
                urllib2.urlopen('http://localhost:%s' % self.port)
            except urllib2.URLError:
                continue
            else:
                break

    def start_wcs_server(self, reset=True):
        if reset == 'False': reset = False
        if reset and os.path.exists('/tmp/.tests'):
            self.stop_wcs_server()
            shutil.rmtree('/tmp/.tests')
        if not os.path.exists('/tmp/.tests'):
            os.mkdir('/tmp/.tests')

        if not reset:
            try:
                urllib2.urlopen('http://localhost:%s' % self.port)
            except urllib2.URLError:
                pass
            else:
                return

        wcs_command = [WCSCTL, 'start',
                '--app-dir', '/tmp/.tests/',
                '--data-dir', WCS_DATA_DIR,
                '--port', str(self.port), '--http', '--silent']
        sp = subprocess.Popen(wcs_command)
        fd = file('/tmp/.tests/pid', 'w')
        fd.write(str(sp.pid))
        fd.close()

        # Wait for the daemons to load themselves
        starttime = time.time()
        self._waitforport(starttime)

    def stop_wcs_server(self):
        if not os.path.exists('/tmp/.tests/pid'):
            return
        fd = file('/tmp/.tests/pid')
        pid = int(fd.read())
        fd.close()
        try:
            # valgrind seems to prefer SIGINT to SIGTERM
            os.kill(pid, signal.SIGINT)
        except OSError, e:
            print >> sys.stderr, 'failed to kill pid %s (%s)' % (pid, e)

    def reset_formdefs(self):
        if os.path.exists('/tmp/.tests/localhost/formdefs'):
            shutil.rmtree('/tmp/.tests/localhost/formdefs')
        if os.path.exists('/tmp/.tests/localhost/formdefs-url_name'):
            shutil.rmtree('/tmp/.tests/localhost/formdefs-url_name')
