/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2005 Bull S.A.
 * Contact: jonas-team@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or 1any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas.jonasadmin.test.resource;

import java.util.Properties;

import junit.framework.TestSuite;

import org.objectweb.jonas.jonasadmin.test.util.JonasAdminAuth;
import org.objectweb.jonas.jonasadmin.test.util.JonasAdminFiles;
import org.objectweb.jonas.jonasadmin.test.util.JonasAdminTestCase;
import org.objectweb.jonas.jonasadmin.test.util.JonasAdminUtils;

import com.meterware.httpunit.HttpUnitOptions;
import com.meterware.httpunit.SubmitButton;
import com.meterware.httpunit.TableCell;
import com.meterware.httpunit.WebForm;
import com.meterware.httpunit.WebLink;
import com.meterware.httpunit.WebResponse;
import com.meterware.httpunit.WebTable;

/**
 * Class for testing datasource Resource
 * @author Paul Kemler
 */
public class F_JonasAdminResourceDatasource extends JonasAdminTestCase {

    /**
     * URL of datasource resource
     */
    private static final String URL_JONASADMIN_DATASOURCE = "EditDeploy.do?type=datasource";

    /**
     * URL of datasource resource
     */
    private static final String URL_JONASADMIN_LIST_DATASOURCES = "ListDatasources.do";

    /**
     * URL of deploy
     */
    private static final String URL_JONASADMIN_DEPLOY = "EditDeploy.do";

    /**
     * URL of create datasource
     */
    private static final String URL_JONASADMIN_CREATE_DATASOURCE = "EditDatasourceProperties.do?action=create";

    /**
     * URL of Datasource resource viewTree
     */
    private static final String URL_JONASADMIN_VIEW_DATASOURCE = "viewTree.do?tree=domain*jonas*resources";

    /**
     * number of tabs when you are in the datasource tabs
     */
    private static final int NUMBER_OF_TABS_FOR_DATASOURCE = 2;

    /**
     * number of tabs when you are in the CONFIRM tabs
     */
    private static final int NUMBER_OF_TABS_FOR_CONFIRM = 3;

    /**
     * number of tabs when you are in the 'new datasource' tabs
     */
    private static final int NUMBER_OF_TABS_FOR_NEW_DATASOURCE = 3;

    /**
     * name of the datasource
     */
    private String name = "";

    /**
     * Constructor with a specified name
     * @param s name
     */
    public F_JonasAdminResourceDatasource(String s) {
        super(s, URL_JONASADMIN);
    }

    /**
     * Main method
     * @param args the arguments
     */
    public static void main(String[] args) {

        String testtorun = null;
        // Get args
        for (int argn = 0; argn < args.length; argn++) {
            String sArg = args[argn];
            if (sArg.equals("-n")) {
                testtorun = args[++argn];
            }
        }
        if (testtorun == null) {
            junit.textui.TestRunner.run(suite());
        } else {
            junit.textui.TestRunner.run(new F_JonasAdminResourceDatasource(testtorun));
        }
    }

    /**
     * Get a new TestSuite for this class
     * @return a new TestSuite for this class
     */
    public static TestSuite suite() {
        return new TestSuite(F_JonasAdminResourceDatasource.class);
    }

    /**
     * Setup need for these tests jonasAdmin is required
     * @throws Exception if it fails
     */
    protected void setUp() throws Exception {
        super.setUp();

        if (wc.getCurrentPage().getURL() == null) {
            useWar("jonasAdmin");
            // login to jonas admin
            try {
                JonasAdminAuth.doValidAuth(wc, url);
            } catch (Exception e) {
                fail("authentification failed :  " + e);
            }
        } else {
            // if there was an error, the connection must be restablished
            try {
                wc.getFrameContents(FRAME_TREE);
            } catch (Exception e) {
                wc.getResponse(urlLogOut);
                // login to jonas admin
                try {
                    JonasAdminAuth.doValidAuth(wc, url);
                } catch (Exception auth) {
                    fail("authentification failed :  " + auth);
                }
            }
        }
    }

    /**
     * Test to deploy and undeploy a datasource
     * @throws Exception if error occurs
     */
    public void testUndeployDeployDatasource() throws Exception {

        WebResponse wr;
        WebLink link;
        WebTable table;
        WebTable tabTable;
        int selectedTab;
        /*
         * To get some utils for WebTable
         */
        JonasAdminUtils utils = new JonasAdminUtils();

        // Disable errors of javascript
        HttpUnitOptions.setExceptionsThrownOnScriptError(false);
        // Disable exception thrown on error status
        HttpUnitOptions.setExceptionsThrownOnErrorStatus(false);

        if (jProp.isDbm()) {
            // Add datasource
            name = "new_datasource";
            Properties properties = new Properties();
            properties.put("datasource.name", name);
            properties.put("datasource.url", "jdbc:hsqldb:hsql://localhost:9001/db_jonas");
            properties.put("datasource.classname", "org.hsqldb.jdbcDriver");
            properties.put("datasource.username", "jonas");
            properties.put("datasource.password", "jonas");
            properties.put("datasource.mapper", "rdb.hsql");
            properties.put("jdbc.connchecklevel", "0");
            properties.put("jdbc.connmaxage", "1440");
            properties.put("jdbc.maxopentime", "60");
            properties.put("jdbc.connteststmt", "select 1");
            properties.put("jdbc.minconpool", "10");
            properties.put("jdbc.maxconpool", "30");
            properties.put("jdbc.samplingperiod", "30");
            properties.put("jdbc.maxwaittime", "5");
            properties.put("jdbc.maxwaiters", "100");

            useDatasource(name, properties);

            // Go to database
            wr = wc.getFrameContents(FRAME_TREE);
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_DATASOURCE);
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 1;

            // Verify tabs
            tabTable = utils.getTabTable(wr);
            testTabs(tabTable, NUMBER_OF_TABS_FOR_DATASOURCE, selectedTab, "Problem in 'Deployment' tab.");
            // - links
            assertTrue("The link " + URL_JONASADMIN_LIST_DATASOURCES + " is not found in the second tab. ", tabTable
                    .getTableCell(0, 2).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_LIST_DATASOURCES));

            String txt = getDeployTable(wr, true);

            if (txt.indexOf(name) == -1) {
                fail("The file" + name + " was not found as deployed.");
            }

            // Undeploy datasource
            WebForm[] webForms = wr.getForms();
            WebForm webForm = webForms[0];

            String params = webForm.getParameterValue("undeploy");
            WebForm.Scriptable script = webForm.getScriptableObject();
            if (params.length() == 0) {
                params += name;
            } else {
                params += "," + name;
            }
            script.setParameterValue("undeploy", params);

            SubmitButton button = webForm.getSubmitButtons()[0];
            button.click();

            // Confirm
            WebResponse submitUndeploy = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 2;

            // Verify tabs
            tabTable = utils.getTabTable(submitUndeploy);
            testTabs(tabTable, NUMBER_OF_TABS_FOR_CONFIRM, selectedTab, "Problem in 'Confirm' tab.");
            // - links
            assertTrue("The link " + URL_JONASADMIN_DEPLOY + " is not found in the first tab. ", tabTable.getTableCell(
                    0, 0).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_DEPLOY));
            assertTrue("The link " + URL_JONASADMIN_LIST_DATASOURCES + " is not found in the third tab. ", tabTable
                    .getTableCell(0, 4).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_LIST_DATASOURCES));

            webForms = submitUndeploy.getForms();
            webForm = webForms[0];

            button = webForm.getSubmitButtons()[0];
            button.click();
            wr = wc.getFrameContents(FRAME_CONTENT);

            // Verify tabs
            tabTable = utils.getTabTable(wr);
            testTabs(tabTable, NUMBER_OF_TABS_FOR_CONFIRM, selectedTab, "Problem in 'Result' tab.");
            // - links
            assertTrue("The link " + URL_JONASADMIN_DEPLOY + " is not found in the first tab. ", tabTable.getTableCell(
                    0, 0).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_DEPLOY));
            assertTrue("The link " + URL_JONASADMIN_LIST_DATASOURCES + " is not found in the third tab. ", tabTable
                    .getTableCell(0, 4).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_LIST_DATASOURCES));

            // Go back to Deployment
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_DEPLOY);
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 1;

            // Verify tabs
            tabTable = utils.getTabTable(wr);
            testTabs(tabTable, NUMBER_OF_TABS_FOR_DATASOURCE, selectedTab, "Problem in 'Deployment' tab.");
            // - links
            assertTrue("The link " + URL_JONASADMIN_LIST_DATASOURCES + " is not found in the second tab. ", tabTable
                    .getTableCell(0, 2).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_LIST_DATASOURCES));

            txt = getDeployTable(wr, true);

            if (txt.indexOf(name) != -1) {
                fail("The jonasAdmin webApp has not removed. " + name);
            }

            // now deploy
            webForms = wr.getForms();
            webForm = webForms[0];

            params = webForm.getParameterValue("deploy");
            script = webForm.getScriptableObject();

            if (params.length() == 0) {
                params += name;
            } else {
                params += "," + name;
            }

            script.setParameterValue("deploy", params);
            button = webForm.getSubmitButtons()[0];
            button.click();

            // Confirm
            submitUndeploy = wc.getFrameContents(FRAME_CONTENT);
            // war is in the table
            webForms = submitUndeploy.getForms();
            webForm = webForms[0];

            button = webForm.getSubmitButtons()[0];
            button.click();

            // Go back to Deployment
            wr = wc.getFrameContents(FRAME_CONTENT);
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_DEPLOY);
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);

            txt = getDeployTable(wr, true);

            if (txt.indexOf(name) == -1) {
                fail("The file " + name + " was not found as deployed.");
            }
        }
    }

    /**
     * Test to create a new datasource
     * @throws Exception if error occurs
     */
    public void testCreateNewDatasource() throws Exception {

        WebResponse wr;
        WebLink link;
        WebTable table;
        WebTable tabTable;
        int selectedTab;
        // Name of the datasource
        name = "new_datasource_";
        // JNDI name The JNDI name to use the datasource
        String jndiName = "";
        // Description Description of the datasource
        String descr = "";
        // URL URL to access to the database
        String urlDatasource = "jdbc:hsqldb:hsql://localhost:9001/db_jonas";
        // JDBC Driver JDBC driver class name to access to the database
        String driver = "org.hsqldb.jdbcDriver";
        // User name User name or login to log in the database
        String user = "jonas";
        // User password User password to log in the database
        String password = "jonas";
        // Mapper Mapper used for the datasource
        String mapper = "rdb.hsql";

        /*
         * To get some utils for WebTable
         */
        JonasAdminUtils utils = new JonasAdminUtils();

        // Disable errors of javascript
        HttpUnitOptions.setExceptionsThrownOnScriptError(false);
        // Disable exception thrown on error status
        HttpUnitOptions.setExceptionsThrownOnErrorStatus(false);

        if (jProp.isDbm()) {
            // Go to database
            wr = wc.getFrameContents(FRAME_TREE);
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_DATASOURCE);
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 1;

            // Go to datasources
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_LIST_DATASOURCES);
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 2;

            // Verify tabs
            tabTable = utils.getTabTable(wr);
            testTabs(tabTable, NUMBER_OF_TABS_FOR_DATASOURCE, selectedTab, "Problem in 'Datasources' tab.");
            // - links
            assertTrue("The link " + URL_JONASADMIN_DEPLOY + " is not found in the first tab. ", tabTable.getTableCell(
                    0, 0).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_DEPLOY));

            // Find a new name
            boolean found = false;
            int i = 0;
            while (!found) {
                if ((wr.getText().indexOf(name + i) == -1)) {
                    name = name + i;
                    jndiName = name;
                    found = true;
                }
                i++;
            }

            // Create a new datasource
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_CREATE_DATASOURCE);
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 3;

            // Verify tabs
            tabTable = utils.getTabTable(wr);
            testTabs(tabTable, NUMBER_OF_TABS_FOR_NEW_DATASOURCE, selectedTab, "Problem in 'New Datasource' tab.");
            // - links
            assertTrue("The link " + URL_JONASADMIN_DEPLOY + " is not found in the first tab. ", tabTable.getTableCell(
                    0, 0).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_DEPLOY));
            assertTrue("The link " + URL_JONASADMIN_LIST_DATASOURCES + " is not found in the third tab. ", tabTable
                    .getTableCell(0, 2).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_LIST_DATASOURCES));

            WebForm form = wr.getForms()[0];
            createNewDatasource(form, name, jndiName, descr, urlDatasource, driver, user, password, mapper);
            wr = wc.getFrameContents(FRAME_CONTENT);

            // Verify if the datasource is deployed
            assertTrue("The created datasource ('" + name + "') is not deployed. ", isLoadedDatasource(name));
            table = utils.getTable(wr, 3);
            int datasourceRow = utils.getRow(name, table, 1).intValue();
            if (datasourceRow == -1) {
                fail("The datasource '" + name + "' is not found in datasource table. Restart jonas and try again. ");
            } else {
                // Verify if there is an image to indicate that the datasource is deployed
                TableCell cell = table.getTableCell(datasourceRow, 0);
                assertEquals("There is no a image to indicate that '" + name + "' datasource is deployed. ", 1, cell.getImages().length);
            }
        }

    }

    /**
     * Test to view empty value error message
     * @throws Exception if error occurs
     */
    public void testCreateDatasourceWithEmptyValue() throws Exception {

        WebResponse wr;
        WebLink link;
        WebTable table;
        WebTable tabTable;
        int selectedTab;
        // Name Name of the datasource
        name = "";
        // JNDI name The JNDI name to use the datasource
        String jndiName = "";
        // Description Description of the datasource
        String descr = "";
        // URL URL to access to the database
        String urlDatasource = "";
        // JDBC Driver JDBC driver class name to access to the database
        String driver = "";
        // User name User name or login to log in the database
        String user = "";
        // User password User password to log in the database
        String password = "";
        // Mapper Mapper used for the datasource
        String mapper = "";

        /*
         * To get some utils for WebTable
         */
        JonasAdminUtils utils = new JonasAdminUtils();

        // Disable errors of javascript
        HttpUnitOptions.setExceptionsThrownOnScriptError(false);
        // Disable exception thrown on error status
        HttpUnitOptions.setExceptionsThrownOnErrorStatus(false);

        if (jProp.isDbm()) {
            // Go to database
            wr = wc.getFrameContents(FRAME_TREE);
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_DATASOURCE);
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 1;

            // Go to datasources
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_LIST_DATASOURCES);
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 2;

            // Create a new datasource
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_CREATE_DATASOURCE);
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 3;

            WebForm form = wr.getForms()[0];
            createNewDatasource(form, name, jndiName, descr, urlDatasource, driver, user, password, mapper);
            wr = wc.getFrameContents(FRAME_CONTENT);

            // Verify error messages
            table = utils.getTable(wr, 0);
            TableCell cell = table.getTableCell(0, 0);

            // class        errors
            assertEquals("The value  of the class attribut of the cell is not 'errors'. ", "errors", cell.getAttribute("class"));
            // Name cannot be empty
            String emptyName = "Name cannot be empty";
            assertTrue("The message '" + emptyName + "' is not found. ", cell.getText().indexOf(emptyName) != -1);
            // JNDI name cannot be empty
            String emptyJndiName = "JNDI name cannot be empty";
            assertTrue("The message '" + emptyJndiName + "' is not found. ", cell.getText().indexOf(emptyJndiName) != -1);
            // JDBC Driver cannot be empty
            String emptyJdbcDriver = "JDBC Driver cannot be empty";
            assertTrue("The message '" + emptyJdbcDriver + "' is not found. ", cell.getText().indexOf(emptyJdbcDriver) != -1);
        }

    }

    /**
     * Tear Down
     * cleanUp action
     */
    public void tearDown() throws Exception {

        if (jProp.isDbm()) {
            // remove created datasource file
            if (!name.equals("")) {
                // Undeploy datasource
                unUseDatasource(name);
                // Delete file
                JonasAdminFiles.deleteConfigFile(name + ".properties");
                name = "";
            }
        }

        super.tearDown();
    }


    /**
     * Return the text of the deployed table or the deployable table
     * @param wr the WebResponse to use
     * @param deployed if true return the text deployed table, if false text of
     *        deployable
     * @return the text of the deployed table or the deployable table
     * @throws Exception if an error occurs
     */
    private String getDeployTable(WebResponse wr, boolean deployed) throws Exception {

        // Extract right table
        JonasAdminUtils utils = new JonasAdminUtils();
        WebTable table = utils.getTable(wr, 0);

        TableCell deployableCell = table.getTableCell(1, 0);
        TableCell deployedCell = table.getTableCell(1, 2);

        if (deployed) {
            return deployedCell.getText();
        } else {
            return deployableCell.getText();
        }
    }

    /**
     * Create a new datasource in jonasAdmin
     * @param form datasource form
     * @param name the name of the datasource
     * @param datasourceName JNDI name
     * @param datasourceDescription the description of the datasource
     * @param datasourceUrl url to access to the databse
     * @param datasourceClassname JDBC driver class name to access to the
     *        database
     * @param datasourceUsername User name or login to log in the database
     * @param datasourcePassword User password to log in the database
     * @param datasourceMapper Mapper used for the datasource
     * @throws Exception if an error occurs when button is clicked.
     */
    private void createNewDatasource(WebForm form, String name, String datasourceName, String datasourceDescription,
            String datasourceUrl, String datasourceClassname, String datasourceUsername, String datasourcePassword,
            String datasourceMapper) throws Exception {
        SubmitButton button = form.getSubmitButtons()[0];

        form.setParameter("name", name);
        form.setParameter("datasourceName", datasourceName);
        form.setParameter("datasourceDescription", datasourceDescription);
        form.setParameter("datasourceUrl", datasourceUrl);
        form.setParameter("datasourceClassname", datasourceClassname);
        form.setParameter("datasourceUsername", datasourceUsername);
        form.setParameter("datasourcePassword", datasourcePassword);
        form.setParameter("datasourceMapper", datasourceMapper);

        button.click();
    }
}