/*
 *  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.impl.wsdl.mock;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.mock.MockRunContext;
import com.eviware.soapui.model.mock.MockRunner;
import com.eviware.soapui.model.propertyexpansion.DefaultPropertyExpansionContext;
import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
import com.eviware.soapui.model.settings.Settings;
import com.eviware.soapui.model.testsuite.TestCase;
import com.eviware.soapui.model.testsuite.TestCaseRunContext;
import com.eviware.soapui.model.testsuite.TestCaseRunner;
import com.eviware.soapui.model.testsuite.TestProperty;
import com.eviware.soapui.model.testsuite.TestStep;
import com.eviware.soapui.support.types.StringToObjectMap;
import com.eviware.soapui.support.types.StringToStringMap;

/**
 * MockRunContext available during dispatching of a WsdlMockRequest
 * 
 * @author ole.matzura
 */

public class WsdlMockRunContext implements MockRunContext, Map<String, Object>, TestCaseRunContext, Cloneable
{
	private DefaultPropertyExpansionContext properties;
	private final WsdlMockService mockService;
	private final WsdlTestRunContext context;
	private WsdlMockResponse mockResponse;

	public WsdlMockRunContext( WsdlMockService mockService, WsdlTestRunContext context )
	{
		this.mockService = mockService;
		this.context = context;

		reset();
	}

	public WsdlMockService getMockService()
	{
		return mockService;
	}

	public Object getProperty( String name )
	{
		return get( name );
	}

	public synchronized boolean hasProperty( String name )
	{
		synchronized( properties )
		{
			return properties.containsKey( name );
		}
	}

	public synchronized Object removeProperty( String name )
	{
		synchronized( properties )
		{
			return properties.remove( name );
		}
	}

	public synchronized void setProperty( String name, Object value )
	{
		if( context != null )
		{
			int ix = name.indexOf( PropertyExpansion.PROPERTY_SEPARATOR );
			if( ix > 0 )
			{
				String teststepname = name.substring( 0, ix );
				TestStep refTestStep = context.getTestCase().getTestStepByName( teststepname );
				if( refTestStep != null )
				{
					TestProperty property = refTestStep.getProperty( name.substring( ix + 1 ) );
					if( property != null && !property.isReadOnly() )
					{
						property.setValue( value.toString() );
						return;
					}
				}
			}
		}

		synchronized( properties )
		{
			properties.put( name, value );
		}
	}

	public synchronized StringToStringMap toStringToStringMap()
	{
		synchronized( properties )
		{
			StringToStringMap result = new StringToStringMap();

			for( String key : properties.keySet() )
			{
				Object value = properties.get( key );
				if( value != null )
					result.put( key, value.toString() );
			}

			return result;
		}
	}

	public synchronized void clear()
	{
		synchronized( properties )
		{
			properties.clear();
		}
	}

	public synchronized Object clone()
	{
		synchronized( properties )
		{
			return properties.clone();
		}
	}

	public synchronized boolean containsKey( Object arg0 )
	{
		synchronized( properties )
		{
			return properties.containsKey( arg0 );
		}
	}

	public synchronized boolean containsValue( Object arg0 )
	{
		synchronized( properties )
		{
			return properties.containsValue( arg0 );
		}
	}

	public synchronized Set<Entry<String, Object>> entrySet()
	{
		synchronized( properties )
		{
			return properties.entrySet();
		}
	}

	public synchronized boolean equals( Object arg0 )
	{
		synchronized( properties )
		{
			return properties.equals( arg0 );
		}
	}

	public synchronized Object get( Object arg0 )
	{
		if( "mockService".equals( arg0 ) )
			return getMockService();

		if( "mockResponse".equals( arg0 ) )
			return getMockResponse();

		if( "modelItem".equals( arg0 ) )
			return getModelItem();

		if( "currentStep".equals( arg0 ) )
			return getCurrentStep();

		if( "currentStepIndex".equals( arg0 ) )
			return getCurrentStepIndex();

		if( "settings".equals( arg0 ) )
			return getSettings();

		if( "testCase".equals( arg0 ) )
			return getTestCase();

		if( "testRunner".equals( arg0 ) )
			return getTestRunner();

		synchronized( properties )
		{
			return properties.get( arg0 );
		}
	}

	public synchronized int hashCode()
	{
		synchronized( properties )
		{
			return properties.hashCode();
		}
	}

	public synchronized boolean isEmpty()
	{
		synchronized( properties )
		{
			return properties.isEmpty();
		}
	}

	public synchronized Set<String> keySet()
	{
		synchronized( properties )
		{
			return properties.keySet();
		}
	}

	public synchronized Object put( String arg0, Object arg1 )
	{
		synchronized( properties )
		{
			return properties.put( arg0, arg1 );
		}
	}

	public synchronized void putAll( Map<? extends String, ? extends Object> arg0 )
	{
		synchronized( arg0 )
		{
			synchronized( properties )
			{
				properties.putAll( arg0 );
			}
		}
	}

	public synchronized Object remove( Object arg0 )
	{
		synchronized( properties )
		{
			return properties.remove( arg0 );
		}
	}

	public synchronized int size()
	{
		synchronized( properties )
		{
			return properties.size();
		}
	}

	public synchronized String toString()
	{
		synchronized( properties )
		{
			return properties.toString();
		}
	}

	public synchronized Collection<Object> values()
	{
		synchronized( properties )
		{
			return properties.values();
		}
	}

	public synchronized TestStep getCurrentStep()
	{
		return context == null ? null : context.getCurrentStep();
	}

	public synchronized int getCurrentStepIndex()
	{
		return context == null ? -1 : context.getCurrentStepIndex();
	}

	public synchronized Object getProperty( String testStep, String propertyName )
	{
		return context == null ? null : context.getProperty( testStep, propertyName );
	}

	public synchronized TestCaseRunner getTestRunner()
	{
		return context == null ? null : context.getTestRunner();
	}

	public synchronized TestCase getTestCase()
	{
		return context == null ? null : context.getTestCase();
	}

	public synchronized Settings getSettings()
	{
		return context == null ? mockService.getSettings() : context.getTestCase().getSettings();
	}

	public void setMockResponse( WsdlMockResponse mockResponse )
	{
		this.mockResponse = mockResponse;
	}

	public WsdlMockResponse getMockResponse()
	{
		return mockResponse;
	}

	public ModelItem getModelItem()
	{
		return mockResponse == null ? mockService : mockResponse;
	}

	public synchronized String expand( String content )
	{
		synchronized( properties )
		{
			return PropertyExpander.expandProperties( this, content );
		}
	}

	public synchronized String[] getPropertyNames()
	{
		synchronized( properties )
		{
			return properties.keySet().toArray( new String[properties.size()] );
		}
	}

	public synchronized StringToObjectMap getProperties()
	{
		synchronized( properties )
		{
			return properties;
		}
	}

	public MockRunner getMockRunner()
	{
		return mockService.getMockRunner();
	}

	public void reset()
	{
		properties = ( DefaultPropertyExpansionContext )( context == null ? new DefaultPropertyExpansionContext(
				mockService ) : context.getProperties() );
	}
}
