/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.servicemix.jbi.servicedesc;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.xml.namespace.QName;

import org.w3c.dom.DocumentFragment;

import org.apache.servicemix.jbi.framework.ComponentNameSpace;

/**
 * Reference generated by NMR to refer to an endpoint registration
 *
 * @version $Revision: 564900 $
 */
public class InternalEndpoint extends AbstractServiceEndpoint {
    
    /**
     * Generated serial version UID
     */
    private static final long serialVersionUID = -2710298087712302015L;
    
    private String endpointName;
    private QName serviceName;
    private Set<QName> interfaces = new HashSet<QName>();
    private transient Map<ComponentNameSpace, InternalEndpoint> remotes = new HashMap<ComponentNameSpace, InternalEndpoint>();
    

    /**
     * Constructor
     * @param componentName
     * @param endpointName
     * @param serviceName
     */
    public InternalEndpoint(ComponentNameSpace componentName, String endpointName, QName serviceName) {
        super(componentName);
        this.endpointName = endpointName;
        this.serviceName = serviceName;
    }
    
    /**
     * Get a reference to this endpoint, using an endpoint reference vocabulary
     * that is known to the provider.
     * @param operationName the name of the operation to be performed by a
     * consumer of the generated endpoint reference. Set to <code>null</code>
     * if this is not applicable.
     * @return endpoint reference as an XML fragment; <code>null</code> if the
     * provider does not support such references.
     */
    public DocumentFragment getAsReference(QName operationName) {
        return EndpointReferenceBuilder.getReference(this);
    }
    
    /**
     * Returns the name of this endpoint.
     * @return the endpoint name.
     */
    public String getEndpointName() {
        return endpointName;
    }
    
    /**
     * Get the qualified names of all the interfaces implemented by this
     * service endpoint.
     * @return array of all interfaces implemented by this service endpoint;
     * must be non-null and non-empty.
     */
    public QName[] getInterfaces() {
        QName[] result = new QName[interfaces.size()];
        interfaces.toArray(result);
        return result;
    }
    
    /**
     * Add an interface
     * @param name
     */
    public void addInterface(QName name) {
        interfaces.add(name);
    }

    /**
     *  Returns the service name of this endpoint.
     *  @return the qualified service name.
     */
    public QName getServiceName() {
        return serviceName;
    }
    
    /**
     * Retrieve all remote component namespaces where this endpoint is activated
     * @return component namespaces
     */
    public InternalEndpoint[] getRemoteEndpoints() {
        InternalEndpoint[] result = new InternalEndpoint[remotes.size()];
        remotes.values().toArray(result);
        return result;
    }
    
    public void addRemoteEndpoint(InternalEndpoint remote) {
        remotes.put(remote.getComponentNameSpace(), remote);
    }
    
    public void removeRemoteEndpoint(InternalEndpoint remote) {
        remotes.remove(remote.getComponentNameSpace());
    }
    
    /**
     * Check if this endpoint is locally activated
     * @return true if the endpoint has been activated locally
     */
    public boolean isLocal() {
        return getComponentNameSpace() != null;
    }
    
    /**
     * Check if the endpoint is remotely activated
     * @return true if the endpoint has been remotely activated
     */
    public boolean isClustered() {
        return remotes != null && remotes.size() > 0;
    }
    
    /**
     * @param obj
     * @return true if equal
     */
    public boolean equals(Object obj) {
        boolean result = false;
        if (obj instanceof InternalEndpoint) {
            InternalEndpoint other = (InternalEndpoint) obj;
            result = other.serviceName.equals(this.serviceName)
                     && other.endpointName.equals(this.endpointName);
        }
        return result;
    }
    
   
    /**
     * @return has code
     */
    public int hashCode() {
        return serviceName.hashCode()
               ^ endpointName.hashCode();
    }
    
    /**
     * @return a pretty print of this
     */
    public String toString() {
        return "ServiceEndpoint[service=" + serviceName + ",endpoint=" + endpointName + "]";
    }

    protected String getClassifier() {
        return "internal";
    }

}