/**
 */
package ua.ansymo.hintco.impl;

import com.google.common.collect.Iterators;

import java.lang.reflect.InvocationTargetException;

import org.eclipse.emf.common.notify.Notification;

import org.eclipse.emf.common.util.EList;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;

import org.eclipse.emf.ecore.impl.ENotificationImpl;

import org.eclipse.xtext.xbase.lib.Functions.Function1;

import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.IteratorExtensions;

import ua.ansymo.hintco.HintcoPackage;
import ua.ansymo.hintco.InputPortInstance;
import ua.ansymo.hintco.OutputPortInstance;
import ua.ansymo.hintco.PortInstance;
import ua.ansymo.hintco.PowerBondAdaptation;
import ua.ansymo.hintco.UnitInstance;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Power Bond Adaptation</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * </p>
 * <ul>
 *   <li>{@link ua.ansymo.hintco.impl.PowerBondAdaptationImpl#getEffort <em>Effort</em>}</li>
 *   <li>{@link ua.ansymo.hintco.impl.PowerBondAdaptationImpl#getFlow <em>Flow</em>}</li>
 *   <li>{@link ua.ansymo.hintco.impl.PowerBondAdaptationImpl#getPOut <em>POut</em>}</li>
 *   <li>{@link ua.ansymo.hintco.impl.PowerBondAdaptationImpl#getPIn <em>PIn</em>}</li>
 *   <li>{@link ua.ansymo.hintco.impl.PowerBondAdaptationImpl#getName <em>Name</em>}</li>
 * </ul>
 *
 * @generated
 */
public class PowerBondAdaptationImpl extends UnitAdaptationImpl implements PowerBondAdaptation {
	/**
	 * The cached value of the '{@link #getEffort() <em>Effort</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getEffort()
	 * @generated
	 * @ordered
	 */
	protected PortInstance effort;

	/**
	 * The cached value of the '{@link #getFlow() <em>Flow</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getFlow()
	 * @generated
	 * @ordered
	 */
	protected PortInstance flow;

	/**
	 * The cached value of the '{@link #getPOut() <em>POut</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getPOut()
	 * @generated
	 * @ordered
	 */
	protected OutputPortInstance pOut;

	/**
	 * The cached value of the '{@link #getPIn() <em>PIn</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getPIn()
	 * @generated
	 * @ordered
	 */
	protected InputPortInstance pIn;

	/**
	 * The default value of the '{@link #getName() <em>Name</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getName()
	 * @generated
	 * @ordered
	 */
	protected static final String NAME_EDEFAULT = null;

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected PowerBondAdaptationImpl() {
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return HintcoPackage.Literals.POWER_BOND_ADAPTATION;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public PortInstance getEffort() {
		if (effort != null && effort.eIsProxy()) {
			InternalEObject oldEffort = (InternalEObject)effort;
			effort = (PortInstance)eResolveProxy(oldEffort);
			if (effort != oldEffort) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE, HintcoPackage.POWER_BOND_ADAPTATION__EFFORT, oldEffort, effort));
			}
		}
		return effort;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public PortInstance basicGetEffort() {
		return effort;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setEffort(PortInstance newEffort) {
		PortInstance oldEffort = effort;
		effort = newEffort;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, HintcoPackage.POWER_BOND_ADAPTATION__EFFORT, oldEffort, effort));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public PortInstance getFlow() {
		if (flow != null && flow.eIsProxy()) {
			InternalEObject oldFlow = (InternalEObject)flow;
			flow = (PortInstance)eResolveProxy(oldFlow);
			if (flow != oldFlow) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE, HintcoPackage.POWER_BOND_ADAPTATION__FLOW, oldFlow, flow));
			}
		}
		return flow;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public PortInstance basicGetFlow() {
		return flow;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setFlow(PortInstance newFlow) {
		PortInstance oldFlow = flow;
		flow = newFlow;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, HintcoPackage.POWER_BOND_ADAPTATION__FLOW, oldFlow, flow));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public OutputPortInstance getPOut() {
		if (pOut != null && pOut.eIsProxy()) {
			InternalEObject oldPOut = (InternalEObject)pOut;
			pOut = (OutputPortInstance)eResolveProxy(oldPOut);
			if (pOut != oldPOut) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE, HintcoPackage.POWER_BOND_ADAPTATION__POUT, oldPOut, pOut));
			}
		}
		return pOut;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public OutputPortInstance basicGetPOut() {
		return pOut;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setPOut(OutputPortInstance newPOut) {
		OutputPortInstance oldPOut = pOut;
		pOut = newPOut;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, HintcoPackage.POWER_BOND_ADAPTATION__POUT, oldPOut, pOut));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public InputPortInstance getPIn() {
		if (pIn != null && pIn.eIsProxy()) {
			InternalEObject oldPIn = (InternalEObject)pIn;
			pIn = (InputPortInstance)eResolveProxy(oldPIn);
			if (pIn != oldPIn) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE, HintcoPackage.POWER_BOND_ADAPTATION__PIN, oldPIn, pIn));
			}
		}
		return pIn;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public InputPortInstance basicGetPIn() {
		return pIn;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setPIn(InputPortInstance newPIn) {
		InputPortInstance oldPIn = pIn;
		pIn = newPIn;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, HintcoPackage.POWER_BOND_ADAPTATION__PIN, oldPIn, pIn));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public String getName() {
		String _xifexpression = null;
		if (((this.getEffort() != null) && (this.getFlow() != null))) {
			String _identifier = this.getEffort().getIdentifier();
			String _plus = ("PBond_" + _identifier);
			String _plus_1 = (_plus + "_");
			String _identifier_1 = this.getFlow().getIdentifier();
			String _plus_2 = (_plus_1 + _identifier_1);
			String _plus_3 = (_plus_2 + "(w=");
			int _weight = this.getWeight();
			String _plus_4 = (_plus_3 + Integer.valueOf(_weight));
			_xifexpression = (_plus_4 + ")");
		}
		else {
			int _weight_1 = this.getWeight();
			String _plus_5 = ("PBond(w=" + Integer.valueOf(_weight_1));
			_xifexpression = (_plus_5 + ")");
		}
		return _xifexpression;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public PowerBondAdaptation getDual() {
		PowerBondAdaptation _xblockexpression = null;
		{
			PowerBondAdaptation res = null;
			if (((this.getEffort() instanceof InputPortInstance) && (this.getFlow() instanceof OutputPortInstance))) {
				final Function1<UnitInstance, Iterable<PowerBondAdaptation>> _function = new Function1<UnitInstance, Iterable<PowerBondAdaptation>>() {
					public Iterable<PowerBondAdaptation> apply(final UnitInstance u) {
						return IteratorExtensions.<PowerBondAdaptation>toIterable(Iterators.<PowerBondAdaptation>filter(u.eAllContents(), PowerBondAdaptation.class));
					}
				};
				final Function1<PowerBondAdaptation, Boolean> _function_1 = new Function1<PowerBondAdaptation, Boolean>() {
					public Boolean apply(final PowerBondAdaptation a) {
						return Boolean.valueOf(((a.getEffort() instanceof OutputPortInstance) && (a.getFlow() instanceof InputPortInstance)));
					}
				};
				final Function1<PowerBondAdaptation, Boolean> _function_2 = new Function1<PowerBondAdaptation, Boolean>() {
					public Boolean apply(final PowerBondAdaptation a) {
						return Boolean.valueOf((((OutputPortInstance) a.getEffort()).getValueTo().contains(PowerBondAdaptationImpl.this.getEffort()) && (((InputPortInstance) a.getFlow()).getValueFrom() == PowerBondAdaptationImpl.this.getFlow())));
					}
				};
				res = IterableExtensions.<PowerBondAdaptation>findFirst(IterableExtensions.<PowerBondAdaptation>filter(IterableExtensions.<UnitInstance, PowerBondAdaptation>flatMap(this.getUnit().getScenario().getCosimunits(), _function), _function_1), _function_2);
			}
			else {
				if (((this.getEffort() instanceof OutputPortInstance) && (this.getFlow() instanceof InputPortInstance))) {
					final Function1<UnitInstance, Iterable<PowerBondAdaptation>> _function_3 = new Function1<UnitInstance, Iterable<PowerBondAdaptation>>() {
						public Iterable<PowerBondAdaptation> apply(final UnitInstance u) {
							return IteratorExtensions.<PowerBondAdaptation>toIterable(Iterators.<PowerBondAdaptation>filter(u.eAllContents(), PowerBondAdaptation.class));
						}
					};
					final Function1<PowerBondAdaptation, Boolean> _function_4 = new Function1<PowerBondAdaptation, Boolean>() {
						public Boolean apply(final PowerBondAdaptation a) {
							return Boolean.valueOf(((a.getEffort() instanceof InputPortInstance) && (a.getFlow() instanceof OutputPortInstance)));
						}
					};
					final Function1<PowerBondAdaptation, Boolean> _function_5 = new Function1<PowerBondAdaptation, Boolean>() {
						public Boolean apply(final PowerBondAdaptation a) {
							return Boolean.valueOf(((((InputPortInstance) a.getEffort()).getValueFrom() == PowerBondAdaptationImpl.this.getEffort()) && ((OutputPortInstance) a.getFlow()).getValueTo().contains(PowerBondAdaptationImpl.this.getFlow())));
						}
					};
					res = IterableExtensions.<PowerBondAdaptation>findFirst(IterableExtensions.<PowerBondAdaptation>filter(IterableExtensions.<UnitInstance, PowerBondAdaptation>flatMap(this.getUnit().getScenario().getCosimunits(), _function_3), _function_4), _function_5);
				}
				else {
					throw new RuntimeException("Invalid effort and flow in power bond adaptation");
				}
			}
			if ((res == null)) {
				throw new RuntimeException("Power bond adaptation has no dual");
			}
			_xblockexpression = res;
		}
		return _xblockexpression;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
			case HintcoPackage.POWER_BOND_ADAPTATION__EFFORT:
				if (resolve) return getEffort();
				return basicGetEffort();
			case HintcoPackage.POWER_BOND_ADAPTATION__FLOW:
				if (resolve) return getFlow();
				return basicGetFlow();
			case HintcoPackage.POWER_BOND_ADAPTATION__POUT:
				if (resolve) return getPOut();
				return basicGetPOut();
			case HintcoPackage.POWER_BOND_ADAPTATION__PIN:
				if (resolve) return getPIn();
				return basicGetPIn();
			case HintcoPackage.POWER_BOND_ADAPTATION__NAME:
				return getName();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
			case HintcoPackage.POWER_BOND_ADAPTATION__EFFORT:
				setEffort((PortInstance)newValue);
				return;
			case HintcoPackage.POWER_BOND_ADAPTATION__FLOW:
				setFlow((PortInstance)newValue);
				return;
			case HintcoPackage.POWER_BOND_ADAPTATION__POUT:
				setPOut((OutputPortInstance)newValue);
				return;
			case HintcoPackage.POWER_BOND_ADAPTATION__PIN:
				setPIn((InputPortInstance)newValue);
				return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
			case HintcoPackage.POWER_BOND_ADAPTATION__EFFORT:
				setEffort((PortInstance)null);
				return;
			case HintcoPackage.POWER_BOND_ADAPTATION__FLOW:
				setFlow((PortInstance)null);
				return;
			case HintcoPackage.POWER_BOND_ADAPTATION__POUT:
				setPOut((OutputPortInstance)null);
				return;
			case HintcoPackage.POWER_BOND_ADAPTATION__PIN:
				setPIn((InputPortInstance)null);
				return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
			case HintcoPackage.POWER_BOND_ADAPTATION__EFFORT:
				return effort != null;
			case HintcoPackage.POWER_BOND_ADAPTATION__FLOW:
				return flow != null;
			case HintcoPackage.POWER_BOND_ADAPTATION__POUT:
				return pOut != null;
			case HintcoPackage.POWER_BOND_ADAPTATION__PIN:
				return pIn != null;
			case HintcoPackage.POWER_BOND_ADAPTATION__NAME:
				return NAME_EDEFAULT == null ? getName() != null : !NAME_EDEFAULT.equals(getName());
		}
		return super.eIsSet(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eInvoke(int operationID, EList<?> arguments) throws InvocationTargetException {
		switch (operationID) {
			case HintcoPackage.POWER_BOND_ADAPTATION___GET_DUAL:
				return getDual();
		}
		return super.eInvoke(operationID, arguments);
	}

} //PowerBondAdaptationImpl
