/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.test.jaxr.common;

import org.jboss.logging.Logger;

import javax.xml.registry.*;
import javax.xml.registry.infomodel.*;
import java.net.*;
import java.util.*;
 
import junit.framework.TestCase;

/**
 * Base class for the Jaxr testsuite
 * @author <mailto:Anil.Saldhana@jboss.org>Anil Saldhana
 */
  public class JaxrTestCase extends  TestCase{
    private static final Logger log = Logger.getLogger(JaxrTestCase.class);
    protected Connection connection = null;
    protected RegistryService registryservice = null;
    protected BusinessLifeCycleManager blcm = null;
    protected BusinessQueryManager bqm = null;
    protected String queryurl = "";
    protected String publishurl = "";
    protected String username = "";
    protected String password = "";

    protected Service service = null;
    protected ServiceBinding  binding = null;

    public JaxrTestCase(){}
    /**
     * Constructor for the JaxrTestCase object
     *
     * @param name Test case name
     */
    public JaxrTestCase(String name) {
        super(name);
        queryurl   = System.getProperty("jaxr.queryurl");
        publishurl = System.getProperty("jaxr.publishurl");
        getLog().debug("queryurl::"+queryurl);
        getLog().debug("publishurl::"+publishurl);
    }

    public void setUp() throws Exception{
        if( connection == null )  connection = this.getConnection();
        if( blcm == null ) blcm = this.getBusinessLifeCycleManager();
    }
    
    public void tearDown() throws Exception{
        if( connection != null) this.releaseConnection();
    }

    /**
     * Test Aunthentication against the JAxr Regisrty
     * @throws Exception
     */
    public void testAuthentication()
      throws Exception
   {
        getLog().debug("Enter testAuthentication");

        if(connection == null ) connection = getConnection();
        assertNotNull("Jaxr Connection is Not Null?",connection);
        authenticate();
        releaseConnection();

        getLog().debug("Exit testAuthentication");
    }
    /**
     * Test obtaining a JaxrConnection
     * @throws Exception
     */
    public void testJaxrConnection()
      throws Exception
   {
        getLog().debug("Enter testJaxrConnection");

        if(connection == null ) connection = getConnection();
        assertNotNull("Jaxr Connection is Not Null?",connection);
        releaseConnection();

        getLog().debug("Exit testJaxrConnection");
    }

    /**
     * Tests the RegistryService
     * @throws Exception
     */
    public void testRegistryService()
      throws Exception
   {
        getLog().debug("Enter testRegistryService");
        if(registryservice == null) registryservice = getRegistryService();
        assertNotNull("RegistryService is Not Null?",registryservice);
        releaseConnection();

        getLog().debug("Exit testRegistryService");
    }

    /**
     * Get a JaxrConnection
     * @return
     * @throws Exception
     */
    protected Connection getConnection()
    throws Exception
   {
        if( connection == null ){
           Properties props = new Properties();
           props.setProperty("javax.xml.registry.queryManagerURL", queryurl);
           props.setProperty("javax.xml.registry.lifeCycleManagerURL", publishurl);
           assertNotNull("QueryUrl is Not Null?",queryurl);
           assertNotNull("PublishUrl is Not Null?",publishurl);

           ConnectionFactory factory = ConnectionFactory.newInstance();
           factory.setProperties(props);
           connection = factory.createConnection();
        }
        return connection;
    }
    /**
     * Get the RegistryService
     * @return
     * @throws Exception
     */
    protected RegistryService getRegistryService()
    throws Exception
   {
        if(connection == null ) connection = getConnection();
        assertNotNull("Jaxr Connection is Not Null?",connection);
        return connection.getRegistryService();
    }
    /**
     * Get the BusinessLifeCycleManager
     * @return
     * @throws Exception
     */
    protected BusinessLifeCycleManager getBusinessLifeCycleManager()
    throws Exception
   {
        if(registryservice == null ) registryservice = getRegistryService();
        assertNotNull("registryservice is Not Null?",registryservice);
        return blcm = registryservice.getBusinessLifeCycleManager();
    }
    /**
     * Get the BusinessQueryManager
     * @return
     * @throws Exception
     */
    protected BusinessQueryManager getBusinessQueryManager()
    throws Exception
   {
        if(registryservice == null ) registryservice = getRegistryService();
        assertNotNull("registryservice is Not Null?",registryservice);
        return bqm = registryservice.getBusinessQueryManager();
    }
    /**
     * Release the Jaxr Connection Object
     * @throws Exception
     */
    protected void releaseConnection()
    throws Exception
   {
        if (connection != null) connection.close();
    }

    /**
     * Authenticate against the registry (Needed before Publish)
     * @throws Exception
     */
    protected void authenticate()
    throws Exception{
      if(connection == null ) connection = getConnection();
      assertNotNull("Jaxr Connection is Not Null?",connection);
      assertNotNull("Username is Not Null?",username);
      assertNotNull("Password is Not Null?",password);

      // Get authorization from the registry
      PasswordAuthentication passwdAuth =
                new PasswordAuthentication(username, password.toCharArray());

      Set creds = new HashSet();
      creds.add(passwdAuth);
      connection.setCredentials(creds);
    }
    /**
     * Get the log
     * @return
     */
    protected Logger getLog() { return log; }


    /**
     * Create an Organization object
     * using JAXR and return the Key
     *
     * @throws Exception
     */
    protected String  createOrganization()
    throws Exception {
        authenticate();
        if( blcm == null ) blcm = this.getBusinessLifeCycleManager();
        assertNotNull("BusinessLifeCycleManager is Not Null?",blcm);
        Organization org = this.getOrganization("JBoss Inc", "Testing Jaxr Org");
        User user = this.getPrimaryContact("Marc Fluery");

        getLog().debug("Created User="+user.getPersonName().getFullName());

        //Email Addresses
        Collection emailadds = new ArrayList();
        emailadds.add(this.getEmailAddress("marc@jboss.org"));
        user.setEmailAddresses(emailadds);

        //Telephone Numbers
        Collection tels = new ArrayList();
        tels.add(this.getTelephoneNumber("121-121-1111"));
        user.setTelephoneNumbers(tels);

        org.setPrimaryContact(user);

        //Classifications
        Collection classifications = new ArrayList();
        classifications.add(this.getClassification("ntis-gov:naics:1997",
                                        "Software Publishers",
                                        "511210"));
        org.addClassifications(classifications);
        getLog().debug("Created Classification");

        //Services and ServiceBindings
        Collection services = new ArrayList();
        if( service == null)
            service = getService("Consulting Service","JBoss Inc provides Consulting");

        getLog().debug("Created Service");

        Collection servicebindings = new ArrayList();
        if( binding == null)
            binding = getServiceBinding("Consulting Arm",false,
                 "http://www.jboss.org" );
        servicebindings.add(binding);
        getLog().debug("Created ServiceBinding");

        getLog().debug("Adding ServiceBindings to Service");
        // Add service bindings to service
        service.addServiceBindings(servicebindings);
        getLog().debug("Added ServiceBindings to Service");

        getLog().debug("Adding Services to Org");
        //Add service
        services.add(service);
        org.addServices(services);
        getLog().debug("Added Services to Org");
        // Add organization and submit to registry
        // Retrieve key if successful
        Collection orgs = new ArrayList();
        orgs.add(org);

        getLog().debug("Going to add the Org into the registry");
        BulkResponse response = blcm.saveOrganizations(orgs);
        Collection exceptions = response.getExceptions();
        assertNull("Org Saving to Registry Successful?", exceptions );
        Collection keys = response.getCollection();
        Iterator keyIter = keys.iterator();

        String id = null;

        if (keyIter.hasNext()) {
            Key orgKey = (Key) keyIter.next();
            id = orgKey.getId();
            System.out.println("Organization key is " + id);
        }
        return id;
    }

    /**
     * Delete an Organization with a given key
     * @param orgkey
     * @throws Exception
     */
    protected void deleteOrganization( Key orgkey)
    throws Exception {
        assertNotNull("Org Key is null?", orgkey);
        authenticate();
        if( blcm == null ) blcm = this.getBusinessLifeCycleManager();
        Collection keys = new ArrayList();
        keys.add(orgkey);

        BulkResponse response = blcm.deleteOrganizations(keys);
        Collection exceptions = response.getExceptions();
        assertNull("Deleting Org with Key="+orgkey,exceptions);
    }

    /**
     * Delete an Organization with a given key
     * @param  keys
     * @throws Exception
     */
    protected void deleteOrganizations( Collection keys)
    throws Exception {
        assertNotNull("Org Key is null?", keys);
        authenticate();
        if( blcm == null ) blcm = this.getBusinessLifeCycleManager();

        BulkResponse response = blcm.deleteOrganizations(keys);
        Collection exceptions = response.getExceptions();
        assertNull("Deleting Orgs ",exceptions);
    }

    //HELPER Methods
    /**
     * Creates an instance of InternationalString
     * @param str
     * @return
     * @throws Exception
     */
    protected InternationalString getIS(String str)
    throws Exception {
        if( blcm == null) blcm = this.getBusinessLifeCycleManager();
         return blcm.createInternationalString(str);
    }
    /**
     * Create a Classification object
     * @param schemename
     * @param name
     * @param value
     * @return
     * @throws Exception
     */
    protected Classification getClassification( String schemename,
                                                String name, String value)
    throws Exception {
        if( bqm == null ) bqm = this.getBusinessQueryManager();
        ClassificationScheme cscheme = bqm.findClassificationSchemeByName(null, schemename);
        return blcm.createClassification( cscheme,name,value );
    }

    /**
     * Create an Organization object
     * @param name
     * @param desc
     * @return
     * @throws Exception
     */
    protected Organization getOrganization(String name, String desc)
    throws Exception {
        if( blcm == null) blcm = this.getBusinessLifeCycleManager();
        Organization org =  blcm.createOrganization(name);
        org.setDescription(getIS(desc));
        return org;
    }
    /**
     * Create a Primary Contact
     * @param name
     * @return
     * @throws Exception
     */
    protected User getPrimaryContact(String name)
    throws Exception {
        if( blcm == null) blcm = this.getBusinessLifeCycleManager();
        User primaryContact = blcm.createUser();
        PersonName personname =  blcm.createPersonName(name);
        primaryContact.setPersonName(personname);
        return  primaryContact;
    }

    /**
     * Create a Telephone Number object
     * @param telnumb
     * @return
     * @throws Exception
     */
    protected  TelephoneNumber getTelephoneNumber(String telnumb )
    throws Exception {
        if( blcm == null) blcm = this.getBusinessLifeCycleManager();
        TelephoneNumber tnum = blcm.createTelephoneNumber();
        tnum.setNumber(telnumb);
        return tnum;
    }

    /**
     * Create an Email Address Object
     * @param email
     * @return
     * @throws Exception
     */
    protected  EmailAddress getEmailAddress(String email )
    throws Exception {
        if( blcm == null) blcm = this.getBusinessLifeCycleManager();
        EmailAddress emailaddress =
                blcm.createEmailAddress(email);
        return emailaddress;
    }
    /**
     * Create a Service
     * @param servicename
     * @param servicedesc
     * @return
     * @throws Exception
     */
    protected Service getService(String servicename, String servicedesc)
    throws Exception {
        if( blcm == null) blcm = this.getBusinessLifeCycleManager();
        if(service == null) {
            service = blcm.createService(servicename);
            service.setDescription(getIS(servicedesc));
        }

        return  service;
    }

    /**
     *  Create a ServiceBinding
     * @param descr
     * @param validateurl  Whether you need to validate the url.
     * @param url
     * @return
     * @throws Exception
     */
    protected ServiceBinding getServiceBinding(String descr, boolean validateurl,
                                               String url)
    throws Exception {
         if( blcm == null) blcm = this.getBusinessLifeCycleManager();
         if( binding == null ){
             binding = blcm.createServiceBinding();
             binding.setDescription(getIS(descr));
             binding.setValidateURI(validateurl);
             binding.setAccessURI(url);
         }

         return binding;
    }
    /**
     * For testing purposes, remove all old organizations lying
     * in the registry with a given name. We will be adding an org
     * and checking its key when we query
     * @param name
     * @throws Exception
     */
    protected void clearOrganizations( String name)
    throws Exception {
        if(bqm  == null )  bqm = this.getBusinessQueryManager();
        Collection findQualifiers = new ArrayList();
        findQualifiers.add(FindQualifier.CASE_SENSITIVE_MATCH);
        Collection namePatterns = new ArrayList();
        namePatterns.add("%" + name + "%");

        // Find orgs with name containing name
        BulkResponse response =
        bqm.findOrganizations(findQualifiers, namePatterns, null,
            null, null, null);
        Collection orgs = response.getCollection();

        System.out.println("There are "+orgs.size()+" orgs to delete");
        Collection keys = new ArrayList();
        Iterator iter = orgs.iterator();
        while( iter.hasNext()){
            Organization org = (Organization)iter.next();
            Key key = org.getKey();
            keys.add(key);
            //this.deleteOrganization(key);
        }
        if( keys != null ) this.deleteOrganizations(keys);

    }

}