/*
 *  soapUI, copyright (C) 2004-2012 smartbear.com 
 *
 *  soapUI is free software; you can redistribute it and/or modify it under the 
 *  terms of version 2.1 of the GNU Lesser General Public License as published by 
 *  the Free Software Foundation.
 *
 *  soapUI 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 at gnu.org.
 */
package com.eviware.soapui.security.actions;

import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;

import com.eviware.soapui.impl.wsdl.support.HelpUrls;
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.project.Project;
import com.eviware.soapui.model.security.SecurityCheckedParameter;
import com.eviware.soapui.model.support.ModelSupport;
import com.eviware.soapui.model.testsuite.TestCase;
import com.eviware.soapui.model.testsuite.TestStep;
import com.eviware.soapui.model.testsuite.TestSuite;
import com.eviware.soapui.security.SecurityTest;
import com.eviware.soapui.security.scan.AbstractSecurityScan;
import com.eviware.soapui.security.scan.AbstractSecurityScanWithProperties;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.action.swing.DefaultActionList;
import com.eviware.x.form.XFormDialog;
import com.eviware.x.form.XFormField;
import com.eviware.x.form.XFormFieldListener;
import com.eviware.x.form.XFormOptionsField;
import com.eviware.x.form.support.ADialogBuilder;
import com.eviware.x.form.support.AField;
import com.eviware.x.form.support.AForm;
import com.eviware.x.form.support.XFormMultiSelectList;
import com.eviware.x.form.support.AField.AFieldType;
import com.eviware.x.impl.swing.JFormDialog;
import com.eviware.x.impl.swing.SwingXFormDialog;

public class CloneParametersAction extends AbstractAction
{

	private XFormDialog dialog;
	protected DefaultActionList actionList;
	private AbstractSecurityScanWithProperties securityScan;

	public CloneParametersAction()
	{
		super( "Clone SecurityScan Parameters" );
		putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clone_parameters.gif" ) );
		putValue( Action.SHORT_DESCRIPTION, "Clones parameter" );
		setEnabled( false );
	}

	public CloneParametersAction( AbstractSecurityScanWithProperties securityScan )
	{
		super( "Clone SecurityScan Parameters" );
		putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clone_parameters.gif" ) );
		putValue( Action.SHORT_DESCRIPTION, "Clones parameter" );
		this.securityScan = securityScan;
	}

	@Override
	public void actionPerformed( ActionEvent e )
	{
		XFormDialog dialog = createCloneParameterDialog();
		dialog.show();
		// model.fireTableDataChanged();
	}

	public void setSecurityScan( AbstractSecurityScanWithProperties securityScan )
	{
		this.securityScan = securityScan;
	}

	private class OkAction extends AbstractAction
	{

		private XFormDialog dialog;

		public OkAction()
		{
			super( "OK" );
		}

		public void setDialog( XFormDialog dialog )
		{
			this.dialog = dialog;
		}

		@Override
		public void actionPerformed( ActionEvent arg0 )
		{
			if( dialog != null )
			{
				( ( SwingXFormDialog )dialog ).setReturnValue( XFormDialog.OK_OPTION );
				List<ModelItem> items = performClone( true );
				UISupport.showInfoMessage( "Updated " + items.size() + " scans" );
				dialog.setVisible( false );
			}
		}
	}

	private String[] getSecurableTestStepsNames( TestCase testCase )
	{
		List<TestStep> testStepList = testCase.getTestStepList();
		List<String> namesList = new ArrayList<String>();
		for( TestStep testStep : testStepList )
		{
			if( AbstractSecurityScan.isSecurable( testStep ) )
			{
				namesList.add( testStep.getName() );
			}
		}
		String[] names = new String[namesList.size()];
		for( int c = 0; c < namesList.size(); c++ )
		{
			names[c] = namesList.get( c );
		}
		return names;
	}

	public List<ModelItem> performClone( boolean showErrorMessage )
	{
		List<ModelItem> items = new ArrayList<ModelItem>();
		String targetTestSuiteName = dialog.getValue( CloneParameterDialog.TARGET_TESTSUITE );
		String targetTestCaseName = dialog.getValue( CloneParameterDialog.TARGET_TESTCASE );
		String targetSecurityTestName = dialog.getValue( CloneParameterDialog.TARGET_SECURITYTEST );
		String targetSecurityTestStepName = dialog.getValue( CloneParameterDialog.TARGET_TESTSTEP );
		String[] targetSecurityScans = StringUtils.toStringArray( ( ( XFormMultiSelectList )dialog
				.getFormField( CloneParameterDialog.TARGET_SECURITYSCAN ) ).getSelectedOptions() );

		if( targetSecurityScans.length == 0 )
		{
			if( showErrorMessage )
			{
				UISupport.showErrorMessage( "No SecurityScans selected.." );
			}
			return items;
		}

		int[] indexes = ( ( XFormOptionsField )dialog.getFormField( CloneParameterDialog.PARAMETERS ) )
				.getSelectedIndexes();
		if( indexes.length == 0 )
		{
			if( showErrorMessage )
			{
				UISupport.showErrorMessage( "No Parameters selected.." );
			}
			return items;
		}

		Project project = securityScan.getTestStep().getTestCase().getTestSuite().getProject();
		TestSuite targetTestSuite = project.getTestSuiteByName( targetTestSuiteName );
		TestCase targetTestCase = targetTestSuite.getTestCaseByName( targetTestCaseName );
		SecurityTest targetSecurityTest = targetTestCase.getSecurityTestByName( targetSecurityTestName );
		TestStep targetTestStep = targetTestCase.getTestStepByName( targetSecurityTestStepName );

		boolean overwrite = dialog.getBooleanValue( CloneParameterDialog.OVERWRITE );

		for( String scanName : targetSecurityScans )
		{
			AbstractSecurityScanWithProperties targetSecurityScan = ( AbstractSecurityScanWithProperties )targetSecurityTest
					.getTestStepSecurityScanByName( targetTestStep.getId(), scanName );

			for( int i : indexes )
			{
				SecurityCheckedParameter scanParameter = securityScan.getParameterAt( i );
				String newParameterLabel = scanParameter.getLabel();
				if( securityScan.getParameterByLabel( scanParameter.getLabel() ) != null )
				{
					if( securityScan.equals( targetSecurityScan ) )
					{
						newParameterLabel = "Copy of " + scanParameter.getLabel();
					}
				}
				if( targetSecurityScan.importParameter( scanParameter, overwrite, newParameterLabel )
						&& !items.contains( targetSecurityScan ) )
				{
					items.add( targetSecurityScan );
				}
			}
		}
		return items;
	}

	private class CancelAction extends AbstractAction
	{

		private XFormDialog dialog;

		public CancelAction()
		{
			super( "Cancel" );
		}

		public void setDialog( XFormDialog dialog )
		{
			this.dialog = dialog;
		}

		@Override
		public void actionPerformed( ActionEvent arg0 )
		{
			if( dialog != null )
			{
				( ( SwingXFormDialog )dialog ).setReturnValue( XFormDialog.CANCEL_OPTION );
				dialog.setVisible( false );
			}
		}
	}

	private class ApplyAction extends AbstractAction
	{

		private XFormDialog dialog;

		public ApplyAction()
		{
			super( "Apply" );
		}

		public void setDialog( XFormDialog dialog )
		{
			this.dialog = dialog;
		}

		@Override
		public void actionPerformed( ActionEvent arg0 )
		{
			if( dialog != null )
			{
				List<ModelItem> items = performClone( true );
				UISupport.showInfoMessage( "Updated " + items.size() + " scans" );

				if( items.size() > 0 )
				{
					( ( XFormMultiSelectList )dialog.getFormField( CloneParameterDialog.TARGET_SECURITYSCAN ) )
							.setSelectedOptions( new String[0] );
					( ( XFormMultiSelectList )dialog.getFormField( CloneParameterDialog.PARAMETERS ) )
							.setSelectedOptions( new String[0] );
				}
			}
		}
	}

	protected XFormDialog createCloneParameterDialog()
	{
		actionList = new DefaultActionList();
		OkAction okAction = new OkAction();
		actionList.addAction( okAction, true );
		CancelAction cancelAction = new CancelAction();
		actionList.addAction( cancelAction );
		ApplyAction applyAction = new ApplyAction();
		actionList.addAction( applyAction );

		dialog = ADialogBuilder.buildDialog( CloneParameterDialog.class, actionList, false );

		okAction.setDialog( dialog );
		cancelAction.setDialog( dialog );
		applyAction.setDialog( dialog );

		final TestCase testCase = securityScan.getTestStep().getTestCase();
		final Project project = testCase.getTestSuite().getProject();

		dialog.getFormField( CloneParameterDialog.TARGET_TESTSUITE ).addFormFieldListener( new XFormFieldListener()
		{
			public void valueChanged( XFormField sourceField, String newValue, String oldValue )
			{
				TestSuite testSuite = project.getTestSuiteByName( newValue );
				String[] testCaseNames = ModelSupport.getNames( testSuite.getTestCaseList() );
				dialog.setOptions( CloneParameterDialog.TARGET_TESTCASE, testCaseNames );

				if( testCaseNames.length > 0 )
				{
					dialog.setValue( CloneParameterDialog.TARGET_TESTCASE, testCaseNames[0] );
					TestCase testCase = testSuite.getTestCaseByName( testCaseNames[0] );

					String[] testStepNames = new String[0];
					String[] securityTestNames = ModelSupport.getNames( testCase.getSecurityTestList() );
					dialog.setOptions( CloneParameterDialog.TARGET_SECURITYTEST, securityTestNames );
					if( securityTestNames.length > 0 )
					{
						testStepNames = getSecurableTestStepsNames( testCase );
					}
					dialog.setOptions( CloneParameterDialog.TARGET_TESTSTEP, testStepNames );

					if( securityTestNames.length > 0 )
					{
						dialog.setValue( CloneParameterDialog.TARGET_SECURITYTEST, securityTestNames[0] );
						if( testStepNames.length > 0 )
						{
							dialog.setValue( CloneParameterDialog.TARGET_TESTSTEP, testStepNames[0] );
						}
						else
						{
							dialog.setOptions( CloneParameterDialog.TARGET_TESTSTEP, new String[0] );
						}

						String securityTestName = dialog.getValue( CloneParameterDialog.TARGET_SECURITYTEST );
						SecurityTest securityTest = testCase.getSecurityTestByName( securityTestName );
						String testStepName = dialog.getValue( CloneParameterDialog.TARGET_TESTSTEP );
						TestStep testStep = testCase.getTestStepByName( testStepName );
						String[] securityScanNames = ModelSupport.getNames( securityTest.getTestStepSecurityScanByType(
								testStep.getId(), AbstractSecurityScanWithProperties.class ) );
						dialog.setOptions( CloneParameterDialog.TARGET_SECURITYSCAN, securityScanNames );
					}
					else
					{
						dialog.setOptions( CloneParameterDialog.TARGET_SECURITYTEST, new String[0] );
						dialog.setOptions( CloneParameterDialog.TARGET_TESTSTEP, new String[0] );
						dialog.setOptions( CloneParameterDialog.TARGET_SECURITYSCAN, new String[0] );
					}
				}
				else
				{
					dialog.setOptions( CloneParameterDialog.TARGET_SECURITYTEST, new String[0] );
					dialog.setOptions( CloneParameterDialog.TARGET_TESTSTEP, new String[0] );
				}
			}
		} );
		dialog.getFormField( CloneParameterDialog.TARGET_TESTCASE ).addFormFieldListener( new XFormFieldListener()
		{
			public void valueChanged( XFormField sourceField, String newValue, String oldValue )
			{
				String testSuiteName = dialog.getValue( CloneParameterDialog.TARGET_TESTSUITE );
				TestSuite testSuite = project.getTestSuiteByName( testSuiteName );
				TestCase testCase = testSuite.getTestCaseByName( newValue );

				String[] testStepNames = new String[0];
				String[] securityTestNames = ModelSupport.getNames( testCase.getSecurityTestList() );
				dialog.setOptions( CloneParameterDialog.TARGET_SECURITYTEST, securityTestNames );
				if( securityTestNames.length > 0 )
				{
					testStepNames = getSecurableTestStepsNames( testCase );
				}
				dialog.setOptions( CloneParameterDialog.TARGET_TESTSTEP, testStepNames );

				if( securityTestNames.length > 0 )
				{
					dialog.setValue( CloneParameterDialog.TARGET_SECURITYTEST, securityTestNames[0] );
					if( testStepNames.length > 0 )
					{
						dialog.setValue( CloneParameterDialog.TARGET_TESTSTEP, testStepNames[0] );
					}
					else
					{
						dialog.setOptions( CloneParameterDialog.TARGET_TESTSTEP, new String[0] );
					}

					String securityTestName = dialog.getValue( CloneParameterDialog.TARGET_SECURITYTEST );
					SecurityTest securityTest = testCase.getSecurityTestByName( securityTestName );
					String testStepName = dialog.getValue( CloneParameterDialog.TARGET_TESTSTEP );
					TestStep testStep = testCase.getTestStepByName( testStepName );
					String[] securityScanNames = ModelSupport.getNames( securityTest.getTestStepSecurityScanByType(
							testStep.getId(), AbstractSecurityScanWithProperties.class ) );
					dialog.setOptions( CloneParameterDialog.TARGET_SECURITYSCAN, securityScanNames );
				}
				else
				{
					dialog.setOptions( CloneParameterDialog.TARGET_SECURITYTEST, new String[0] );
					dialog.setOptions( CloneParameterDialog.TARGET_TESTSTEP, new String[0] );
					dialog.setOptions( CloneParameterDialog.TARGET_SECURITYSCAN, new String[0] );
				}
			}
		} );
		dialog.getFormField( CloneParameterDialog.TARGET_TESTSTEP ).addFormFieldListener( new XFormFieldListener()
		{
			public void valueChanged( XFormField sourceField, String newValue, String oldValue )
			{
				String testSuiteName = dialog.getValue( CloneParameterDialog.TARGET_TESTSUITE );
				TestSuite testSuite = project.getTestSuiteByName( testSuiteName );
				String testCaseName = dialog.getValue( CloneParameterDialog.TARGET_TESTCASE );
				TestCase testCase = testSuite.getTestCaseByName( testCaseName );
				String securityTestName = dialog.getValue( CloneParameterDialog.TARGET_SECURITYTEST );
				SecurityTest securityTest = testCase.getSecurityTestByName( securityTestName );
				TestStep testStep = testCase.getTestStepByName( newValue );

				String[] securityScanNames = ModelSupport.getNames( securityTest.getTestStepSecurityScanByType(
						testStep.getId(), AbstractSecurityScanWithProperties.class ) );
				dialog.setOptions( CloneParameterDialog.TARGET_SECURITYSCAN, securityScanNames );
			}
		} );
		dialog.getFormField( CloneParameterDialog.TARGET_SECURITYTEST ).addFormFieldListener( new XFormFieldListener()
		{
			public void valueChanged( XFormField sourceField, String newValue, String oldValue )
			{
				String testSuiteName = dialog.getValue( CloneParameterDialog.TARGET_TESTSUITE );
				TestSuite testSuite = project.getTestSuiteByName( testSuiteName );
				String testCaseName = dialog.getValue( CloneParameterDialog.TARGET_TESTCASE );
				TestCase testCase = testSuite.getTestCaseByName( testCaseName );
				SecurityTest securityTest = testCase.getSecurityTestByName( newValue );
				String testStepName = dialog.getValue( CloneParameterDialog.TARGET_TESTSTEP );
				TestStep testStep = testCase.getTestStepByName( testStepName );

				String[] securityScanNames = ModelSupport.getNames( securityTest.getTestStepSecurityScanByType(
						testStep.getId(), AbstractSecurityScanWithProperties.class ) );
				dialog.setOptions( CloneParameterDialog.TARGET_SECURITYSCAN, securityScanNames );
			}
		} );

		WsdlTestCase wsdlTestCase = ( WsdlTestCase )securityScan.getTestStep().getTestCase();

		dialog.setOptions( CloneParameterDialog.TARGET_TESTSUITE,
				ModelSupport.getNames( wsdlTestCase.getTestSuite().getProject().getTestSuiteList() ) );
		dialog.setValue( CloneParameterDialog.TARGET_TESTSUITE, wsdlTestCase.getTestSuite().getName() );

		List<TestCase> wsdlTestCaseList = wsdlTestCase.getTestSuite().getTestCaseList();
		dialog.setOptions( CloneParameterDialog.TARGET_TESTCASE, ModelSupport.getNames( wsdlTestCaseList ) );
		dialog.setValue( CloneParameterDialog.TARGET_TESTCASE, wsdlTestCase.getName() );

		dialog.setOptions( CloneParameterDialog.TARGET_TESTSTEP, getSecurableTestStepsNames( wsdlTestCase ) );
		dialog.setOptions( CloneParameterDialog.TARGET_SECURITYTEST,
				ModelSupport.getNames( wsdlTestCase.getSecurityTestList() ) );

		String securityTestName = dialog.getValue( CloneParameterDialog.TARGET_SECURITYTEST );
		SecurityTest securityTest = wsdlTestCase.getSecurityTestByName( securityTestName );
		String testStepName = dialog.getValue( CloneParameterDialog.TARGET_TESTSTEP );
		TestStep testStep = wsdlTestCase.getTestStepByName( testStepName );

		String[] securityScanNames = ModelSupport.getNames( securityTest.getTestStepSecurityScanByType( testStep.getId(),
				AbstractSecurityScanWithProperties.class ) );
		dialog.setOptions( CloneParameterDialog.TARGET_SECURITYSCAN, securityScanNames );

		dialog.setOptions( CloneParameterDialog.PARAMETERS, securityScan.getParameterHolder().getParameterLabels() );

		( ( JFormDialog )dialog ).getDialog().setResizable( false );

		return dialog;
	}

	@AForm( description = "Specify target TestSuite/TestCase/Security Test(s)/Security Scan(s) and select Parameters to clone", name = "Clone Parameters", icon = UISupport.TOOL_ICON_PATH, helpUrl = HelpUrls.SECURITY_SCANS_OVERVIEW )
	private interface CloneParameterDialog
	{
		@AField( name = "Parameters", description = "The Parameters to clone", type = AFieldType.MULTILIST )
		public final static String PARAMETERS = "Parameters";

		@AField( name = "Target TestSuite", description = "The target TestSuite for the cloned Parameter(s)", type = AFieldType.ENUMERATION )
		public final static String TARGET_TESTSUITE = "Target TestSuite";

		@AField( name = "Target TestCase", description = "The target TestCase for the cloned Parameter(s)", type = AFieldType.ENUMERATION )
		public final static String TARGET_TESTCASE = "Target TestCase";

		@AField( name = "Target SecurityTest", description = "The target SecurityTest for the cloned Parameter(s)", type = AFieldType.ENUMERATION )
		public final static String TARGET_SECURITYTEST = "Target SecurityTest";

		@AField( name = "Target TestStep", description = "The target TestStep for the cloned Parameter(s)", type = AFieldType.ENUMERATION )
		public final static String TARGET_TESTSTEP = "Target TestStep";

		@AField( name = "Target SecurityScans", description = "The SecurityScans to clone to", type = AFieldType.MULTILIST )
		public final static String TARGET_SECURITYSCAN = "Target SecurityScans";

		@AField( name = "Overwrite", description = "Overwrite existing parameters", type = AFieldType.BOOLEAN )
		public final static String OVERWRITE = "Overwrite";
	}

}
