package com.fujitsu.iflowqa.testframe;

import org.apache.slide.urm.authenticator.URMAdministrator;
import org.apache.slide.urm.authenticator.URMAuthenticator;
import org.apache.slide.urm.authenticator.userdb.URMGroup;
import org.apache.slide.urm.common.URMConfigurator;
import org.apache.slide.urm.common.URMConstants;
import org.apache.slide.urm.common.URMPrincipal;
import org.apache.slide.urm.common.impl.URMConfiguratorXML;

import com.fujitsu.iflow.common.SystemEnvironment;
import com.fujitsu.iflow.model.wfcore.ProfilePropImpl;
import com.fujitsu.iflow.model.workflow.DirectoryServices;
import com.fujitsu.iflow.model.workflow.ProfileProp;
import com.fujitsu.iflow.model.workflow.WFObjectFactory;

/**
 * <p> TestIBPMSSXAdapter class is designed to test all the directory services api's for the
 * IBPM SSX Adapter implementation.</p>
 * <p> IBPM sserver must be running before executing this test. </p>
 * <p> This test class is added as part of the smoke test package, it will be run as the standard
 * testing by smoketest as long as the IBPM is using the IMR/SSX adapter as Directory server, for
 * all other directory service adapter this test case will be ignored.</p>
 * <p> This test case can also be run as the standalone test case with the smoketest TestDriver class.
 * To run this test case standalone follwing environment setting needs to be performed. </p>
 * <p> Instructions to run this test case standalone -
 * 1) Install AITS (Smoketest.zip)
 * 2) On a DOS command window run "0.TWFInit.bat"
 * 3) Change directory to <BPM install Dir>/bin/Aits
 * 4) Execute following command on the DOS window </p>
 * <b>java com.fujitsu.iflowqa.testframe.TestDriver com.fujitsu.iflowqa.testframe.TestIBPMSSXAdapter </b>
 */
public class TestIBPMSSXAdapter extends BPMTestBase
{
    SystemEnvironment sysEnv = null;
    String adminUserDomain = null;

    URMAdministrator urmadmin = null;
    String testUser1 = null;
    String testUser2 = null;
    String testUser3 = null;
    String testGroup = null;

    public TestIBPMSSXAdapter()
    {
        super();
    }

    /*
     * This method runs the rest.
     */
    public void runTests(TestRecorder recorder) throws Exception {
        init(recorder);
        try
        {
            sysEnv = new SystemEnvironment(tr.getRequiredProperty("InitFile"));
            int dirOption = sysEnv.vTWFDirectoryService;
            if(dirOption == 4)
            {
                try
                {
                    urmadmin = getURMAuthenticator();
                    //create 2 users into SSX
                    testUser1 = "testuser_ssx1";
                    String testUserPwd1 = "ssxuser1pwd";
                    urmadmin.createUser(testUser1,testUserPwd1.toCharArray(),adminUserDomain);
                    testUser2 = "testuser_ssx2";
                    String testUserPwd2 = "ssxuser2pwd";
                    urmadmin.createUser(testUser2,testUserPwd2.toCharArray(),adminUserDomain);
                    //create a group
                    testGroup = "TestGroup_SSX";
                    urmadmin.createGroup(testGroup,adminUserDomain);
                    //add newly created users to this group
                    URMGroup grp = urmadmin.getGroup(testGroup, adminUserDomain);
                    grp.addUserToGroup(testUser1, adminUserDomain);
                    grp.addUserToGroup(testUser2, adminUserDomain);

                    //login into IBPM
                    login();
                    DirectoryServices dirService = WFObjectFactory.getDirectoryServices(wfSession,username,password);
                    // validate users retrieved from a group
                    validateUsers(dirService);

                    //refresh group test
                    refreshGroup(dirService);

                    // validate create user prop test
                    validCreateUserProp(dirService);

                    //validate the updated user property
                    validUpdateUserProp(dirService);

                    //validate delete user profile
                    validDeleteUserProp(dirService);
                }
                catch(Exception ex)
                {
                    tr.markFailed("IBPM SSX Adapter Directory test case failed",ex.getMessage());
                }
                finally
                {
                    //delete all the created users and groups
                    if(adminUserDomain == null)
                        adminUserDomain = "";
                    if(testUser1 != null)
                        urmadmin.deleteUser(testUser1, adminUserDomain);
                    if(testUser2 != null)
                        urmadmin.deleteUser(testUser2, adminUserDomain);
                    if(testUser3 != null)
                        urmadmin.deleteUser(testUser3, adminUserDomain);
                    if(testGroup != null)
                        urmadmin.deleteGroup(testGroup, adminUserDomain);
                }
            }
            else
            {
                tr.markPassed("Directory Adapter is NOT using the IMR/SSX Directory server.");
            }
        } catch (Exception e) {
            throw new ExceptionWrapper("Exception caught in main test level", e);
        }
    }

    /**
     * <p> Tests the newly created users and Groups can be retrieved from the
     * IBPMSSX Directory service adapter.
     * @param directoryServ
     * @throws Exception
     */
    private
    void
    validateUsers(DirectoryServices directoryServ) throws Exception
    {
        String[] users = directoryServ.getUserList(testGroup);
        boolean isFound = false;
        int noUsers = users.length;
        for(int i=0; i<noUsers; i++)
        {
            if(users[i].equalsIgnoreCase(testUser1) || users[i].equalsIgnoreCase(testUser2))
            {
                isFound = true;
                continue;
            }
            else
            {
                isFound = false;
                break;
            }
        }
        if(isFound )
            tr.markPassed("Successfully retireved all users from the Group: "+testGroup);
        else
        {
            StringBuffer userList = new StringBuffer();
            for(int j=0; j<users.length; j++)
            {
                if(userList.length() <= 0)
                    userList.append(users[j]);
                else
                    userList.append(","+users[j]);
            }
            tr.markFailed("Retrieving of users from a group failed","Expected users: "+testUser1+","+testUser2+" But retrieved following users: "+userList);
        }
    }

    /**
     * Creates user profile and retrieves to see the created profile exists for
     * the user.
     * @param directoryServ
     * @throws Exception
     */
    private
    void
    validCreateUserProp(DirectoryServices directoryServ) throws Exception
    {
        // test user property, create user property
        StringBuffer propBuff = new StringBuffer();
        String reqUserProp = sysEnv.vRequiredUserAttribute;
        String[] crUserProp = reqUserProp.split(",");
        int propLen = crUserProp.length;
        ProfileProp[] crProfile = new ProfileProp[propLen];
        for(int c=0; c<propLen; c++)
        {
            String[] comVal= new String[1];
            comVal[0] = "testValUserProp";
            ProfilePropImpl newProfile = new ProfilePropImpl(crUserProp[c],"String",comVal);
            if(newProfile.getName().equals("dmsdir"))
            {
                String[] dmsPath = sysEnv.vDMSRoot.split(",");
                String[] dmsVal = new String[1];
                dmsVal[0]=dmsPath[0]+"testSSXDmsDir";
                newProfile.setValues(dmsVal);
            }
            crProfile[c] = newProfile;
        }
        directoryServ.createUserPropList(testUser1, crProfile);
        tr.markPassed("Successfully created user property for user '"+testUser1+"'");
        // retrieve the user property
        ProfileProp[] profile = directoryServ.getUserAllPropList(testUser1);
        for(int p=0; p<profile.length; p++)
        {
            if(propBuff.length() <= 0)
                propBuff.append(profile[p].getName());
            else
                propBuff.append(","+profile[p].getName());
            String[] values = profile[p].getValues();
        }
        if(reqUserProp.indexOf(propBuff.toString()) != -1)
            tr.markPassed("Successfully retrieved all the required user property for user '"+testUser1+"'"+propBuff);
        else
            tr.markFailed("Retrieving user property list failed","Expected properties '"+reqUserProp+"' But retrieved '"+propBuff+"'");
    }

    /**
     * Test the newly added user in the group can be retrieved without restarting the
     * directory service, same for the removing of user.
     * @param directoryServ
     * @throws Exception
     */
    private
    void
    refreshGroup(DirectoryServices directoryServ) throws Exception
    {
        // create a new user and add it to a same group
        testUser3 = "testuser_ssx3";
        String testUserPwd3 = "ssxuser3pwd";
        urmadmin.createUser(testUser3,testUserPwd3.toCharArray(),adminUserDomain);
        //add newly created users to this group
        URMGroup grpOrig = urmadmin.getGroup(testGroup, adminUserDomain);
        grpOrig.addUserToGroup(testUser3, adminUserDomain);
        // now refresh the group list
        wfSession.resetLDAPGroupsList();
        // Now again retriee all users from the same group and check if this newly
        // added user present in this group
        boolean newUserFound = false;
        String[] usersNew = directoryServ.getUserList(testGroup);
        for(int k=0; k<usersNew.length; k++)
        {
            if(usersNew[k].equalsIgnoreCase(testUser3))
            {
                newUserFound = true;
                break;
            }
        }
        if(newUserFound)
            tr.markPassed("Successfully refreshed group, retireved newly added user '"+testUser3+"'"+" from the Group '"+testGroup+"'");
        else
            tr.markFailed("Refresh Group failed","Expected user '"+testUser3+"'"+" in group '"+testGroup+"'");

        // test removing user from a group
        grpOrig = urmadmin.getGroup(testGroup, adminUserDomain);
        grpOrig.removeUserFromGroup(testUser3, adminUserDomain);
        //check to see, if the user is successfully removed from the group
        // now refresh the group list
        wfSession.resetLDAPGroupsList();
        newUserFound = false;
        usersNew = directoryServ.getUserList(testGroup);
        for(int m=0; m<usersNew.length; m++)
        {
            if(usersNew[m].equalsIgnoreCase(testUser3))
            {
                newUserFound = true;
                break;
            }
        }
        if(!newUserFound)
            tr.markPassed("Successfully refreshed group, '"+testUser3+"' sucessfully removed from the Group '"+testGroup+"'");
        else
            tr.markFailed("Refresh Group failed","user '"+testUser3+"' still present in the group '"+testGroup+"'");
    }

    /**
     * Tests to check the newly updated user property value can be retrieved by the
     * Directory service adapter.
     * @param directoryServ
     * @throws Exception
     */
    private
    void
    validUpdateUserProp(DirectoryServices directoryServ) throws Exception
    {
        // update the user property email and iflownotification and check the updated value
        String[] strEmailVal= new String[1];
        strEmailVal[0] = testUser1+"@us.fujitsu.com";
        ProfilePropImpl emailProfile = new ProfilePropImpl("email","String",strEmailVal);
        String[] strNotVal = new String[1];
        strNotVal[0] = "yes";
        ProfilePropImpl iflownotProfile = new ProfilePropImpl("iflownotification","String",strNotVal);
        ProfilePropImpl[] updateProfile = new ProfilePropImpl[3];
        updateProfile[0] = emailProfile;
        updateProfile[1] = iflownotProfile;
        directoryServ.updateUserPropList(testUser1,updateProfile);
        //check the updated value
        boolean updateSuccess = false;
        ProfileProp[] retProfile = directoryServ.getUserAllPropList(testUser1);
        String[] retEmailVal = new String[0];
        String[] retIflowNotVal = new String[0];
        for(int u=0; u<retProfile.length; u++)
        {
            if(retProfile[u].getName().equals("email"))
            {
                retEmailVal = retProfile[u].getValues();
                if(retEmailVal[0].equals(strEmailVal[0]))
                    updateSuccess = true;
                else
                    updateSuccess = false;
            }
            if(retProfile[u].getName().equals("iflownotification"))
            {
                retIflowNotVal = retProfile[u].getValues();
                if(retIflowNotVal[0].equals(strNotVal[0]))
                    updateSuccess = true;
                else
                    updateSuccess = false;
            }
        }
        if(updateSuccess)
            tr.markPassed("Successfully updated user property for user '"+testUser1+"'");
        else
            tr.markFailed("Updating user profile failed","Expected properties '"+strEmailVal[0]+","+ strNotVal[0]+"' But retrieved '"+retEmailVal[0]+","+retIflowNotVal[0]+"'");
    }

    /**
     * Tests to check the newly updated user property value can be deleted by the
     * Directory service adapter.
     * @param directoryServ
     * @throws Exception
     */
    private
    void
    validDeleteUserProp(DirectoryServices directoryServ) throws Exception
    {
        boolean deleteSuccess = true;
        directoryServ.deleteUserPropList(testUser1);
        ProfileProp[] retProfile = directoryServ.getUserAllPropList(testUser1);
        String propName = null;
        String[] propValue = new String[0];
        for(int u=0; u<retProfile.length; u++)
        {
            propValue = retProfile[u].getValues();
            if(propValue[0].length() > 0)
            {
                propName = retProfile[u].getName();
                propValue = retProfile[u].getValues();
                deleteSuccess = false;
                break;
            }
        }

        if(deleteSuccess)
            tr.markPassed("Successfully Deleted user property for user '"+testUser1+"'");
        else
            tr.markFailed("Deleting user profile failed","Expected 'Empty' values for all the properties, But retrieved value '"+propValue[0]+"' for property '"+propName+"'");
    }

    /**
     * Utility mthod to create the adminsitrative object by authenticating
     * the user agains the Admin Role of the SSX component.
     * @return URMAdministrator
     * @throws Exception
     */
    private
    URMAdministrator
    getURMAuthenticator() throws Exception
    {
        // load the urm configuration file, this file will be read from the
        // environment variable URM_CONFIGFILE_PATH, make sure to set this param
        System.setProperty("URM_CONFIGFILE_PATH",sysEnv.vURMConfigFilePath);
        URMConfigurator conf = URMConfiguratorXML.newConfigfileConfigurator();
        conf = (URMConfigurator)(conf.getSubConfigurators().get("Authenticator"));
        URMAuthenticator authenticator = URMAuthenticator.newInstance(conf);

        // Authenticates the user set by the LDAPAccessUserId and LDAPAccessUserPassword for the
        // default domain, the user must have the administrative privilege to access
        // the directory server
        adminUserDomain = sysEnv.vURMDomain;
        String adminUser = sysEnv.vLDAPAccessUserID;
        int dIndex = -1;
        if((dIndex = adminUser.indexOf("\\")) != -1 )
        {
            adminUserDomain = adminUser.substring(0,dIndex);
            adminUser = adminUser.substring(dIndex+1);
        }
        if(adminUserDomain != null && adminUserDomain.trim().length() == 0)
            adminUserDomain = null;
        URMPrincipal principal = authenticator.authenticateUser(adminUser,
                                    sysEnv.vLDAPAccessUserPassword.toCharArray(), adminUserDomain);
        principal.setActiveRole(URMConstants.URM_ADMIN_ROLE);
        return principal.getURMAdministrator();
    }

}