/*
 * 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.ode.bpel.memdao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.ode.bpel.common.BpelEventFilter;
import org.apache.ode.bpel.common.Filter;
import org.apache.ode.bpel.common.InstanceFilter;
import org.apache.ode.bpel.common.ProcessFilter;
import org.apache.ode.bpel.dao.BpelDAOConnection;
import org.apache.ode.bpel.dao.CorrelationSetDAO;
import org.apache.ode.bpel.dao.MessageExchangeDAO;
import org.apache.ode.bpel.dao.ProcessDAO;
import org.apache.ode.bpel.dao.ProcessInstanceDAO;
import org.apache.ode.bpel.dao.ScopeDAO;
import org.apache.ode.bpel.evt.BpelEvent;
import org.apache.ode.bpel.iapi.Scheduler;
import org.apache.ode.utils.ISO8601DateParser;
import org.apache.ode.utils.stl.CollectionsX;
import org.apache.ode.utils.stl.UnaryFunction;

import javax.xml.namespace.QName;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.ConcurrentHashMap;


/**
 * A very simple, in-memory implementation of the {@link BpelDAOConnection} interface.
 */
class BpelDAOConnectionImpl implements BpelDAOConnection {
    private static final Logger __log = LoggerFactory.getLogger(BpelDAOConnectionImpl.class);

    private Scheduler _scheduler;
    private Map<QName, ProcessDaoImpl> _store;
    private List<BpelEvent> _events = new LinkedList<BpelEvent>();
    long _mexTtl;

    private static Map<String,MessageExchangeDAO> _mexStore = Collections.synchronizedMap(new HashMap<String,MessageExchangeDAO>());
    protected static Map<String, Long> _mexAge = new ConcurrentHashMap<String, Long>();
    private static AtomicLong counter = new AtomicLong(Long.MAX_VALUE / 2);
    private static volatile long _lastRemoval = 0;

    BpelDAOConnectionImpl(Map<QName, ProcessDaoImpl> store, Scheduler scheduler, long mexTtl) {
        _store = store;
        _scheduler = scheduler;
        _mexTtl = mexTtl;
    }

    public ProcessDAO getProcess(QName processId) {
        return _store.get(processId);
    }

    public ProcessDAO createTransientProcess(Long id) {
        ProcessDaoImpl process = new ProcessDaoImpl(this, _store, null, null, null, 0);

        return process;
    }

    public ProcessDAO createProcess(QName pid, QName type, String guid, long version) {
        ProcessDaoImpl process = new ProcessDaoImpl(this,_store,pid,type, guid,version);
        _store.put(pid,process);
        return process;
    }

    public ProcessInstanceDAO getInstance(Long iid) {
        for (ProcessDaoImpl proc : _store.values()) {
            ProcessInstanceDAO instance = proc._instances.get(iid);
            if (instance != null)
                return instance;
        }
        return null;
    }

    public int getNumInstances(QName processId) {
        ProcessDAO process = getProcess(processId);
        if (process != null)
            return process.getNumInstances();
        else return -1;
    }

    @SuppressWarnings("unchecked")
    public Collection<ProcessInstanceDAO> instanceQuery(InstanceFilter filter) {
        if(filter.getLimit()==0) {
            return Collections.EMPTY_LIST;
        }
        List<ProcessInstanceDAO> matched = new ArrayList<ProcessInstanceDAO>();
        // Selecting
        selectionCompleted:
        for (ProcessDaoImpl proc : _store.values()) {
            boolean pmatch = true;
            if (filter.getNameFilter() != null
                    && !equalsOrWildcardMatch(filter.getNameFilter(), proc.getProcessId().getLocalPart()))
                pmatch = false;
            if (filter.getNamespaceFilter() != null
                    && !equalsOrWildcardMatch(filter.getNamespaceFilter(), proc.getProcessId().getNamespaceURI()))
                pmatch = false;

            if (pmatch) {
                for (ProcessInstanceDAO inst : proc._instances.values()) {
                    boolean match = true;

                    if (filter.getStatusFilter() != null) {
                        boolean statusMatch = false;
                        for (Short status : filter.convertFilterState()) {
                            if (inst.getState() == status.byteValue()) statusMatch = true;
                        }
                        if (!statusMatch) match = false;
                    }
                    if (filter.getStartedDateFilter() != null
                            && !dateMatch(filter.getStartedDateFilter(), inst.getCreateTime(), filter))
                        match = false;
                    if (filter.getLastActiveDateFilter() != null
                            && !dateMatch(filter.getLastActiveDateFilter(), inst.getLastActiveTime(), filter))
                        match = false;

//                    if (filter.getPropertyValuesFilter() != null) {
//                        for (Map.Entry propEntry : filter.getPropertyValuesFilter().entrySet()) {
//                            boolean entryMatched = false;
//                            for (ProcessPropertyDAO prop : proc.getProperties()) {
//                                if (prop.getName().equals(propEntry.getKey())
//                                        && (propEntry.getValue().equals(prop.getMixedContent())
//                                        || propEntry.getValue().equals(prop.getSimpleContent()))) {
//                                    entryMatched = true;
//                                }
//                            }
//                            if (!entryMatched) {
//                                match = false;
//                            }
//                        }
//                    }

                    if (match) {
                        matched.add(inst);
                        if(matched.size()==filter.getLimit()) {
                            break selectionCompleted;
                        }
                    }
                }
            }
        }
        // And ordering
        if (filter.getOrders() != null) {
            final List<String> orders = filter.getOrders();

            Collections.sort(matched, new Comparator<ProcessInstanceDAO>() {
                public int compare(ProcessInstanceDAO o1, ProcessInstanceDAO o2) {
                    for (String orderKey: orders) {
                        int result = compareInstanceUsingKey(orderKey, o1, o2);
                        if (result != 0) return result;
                    }
                    return 0;
                }
            });
        }

        return matched;
    }

    /**
     * Close this DAO connection.
     */
    public void close() {
    }

    public Collection<ProcessDAO> processQuery(ProcessFilter filter) {
        throw new UnsupportedOperationException("Can't query process configuration using a transient DAO.");
    }

    public MessageExchangeDAO createMessageExchange(char dir) {
        final String id = Long.toString(counter.getAndIncrement());
        MessageExchangeDAO mex = new MessageExchangeDAOImpl(dir,id);
        long now = System.currentTimeMillis();
        _mexStore.put(id,mex);
        _mexAge.put(id, now);

        if (now > _lastRemoval + (_mexTtl / 10)) {
            _lastRemoval = now;
            Object[] oldMexs = _mexAge.keySet().toArray();
            for (int i=oldMexs.length-1; i>0; i--) {
                String oldMex = (String) oldMexs[i];
                Long age = _mexAge.get(oldMex);
                if (age != null && now-age > _mexTtl) {
                    removeMessageExchange(oldMex);
                    _mexAge.remove(oldMex);
                }
            }
        }

        // Removing right away on rollback
        onRollback(new Runnable() {
            public void run() {
                removeMessageExchange(id);
                _mexAge.remove(id);
            }
        });

        return mex;
    }

    public MessageExchangeDAO getMessageExchange(String mexid) {
        return _mexStore.get(mexid);
    }

    private int compareInstanceUsingKey(String key, ProcessInstanceDAO instanceDAO1, ProcessInstanceDAO instanceDAO2) {
        String s1 = null;
        String s2 = null;
        boolean ascending = true;
        String orderKey = key;
        if (key.startsWith("+") || key.startsWith("-")) {
            orderKey = key.substring(1, key.length());
            if (key.startsWith("-")) ascending = false;
        }
        ProcessDAO process1 = getProcess(instanceDAO1.getProcess().getProcessId());
        ProcessDAO process2 = getProcess(instanceDAO2.getProcess().getProcessId());
        if ("pid".equals(orderKey)) {
            s1 = process1.getProcessId().toString();
            s2 = process2.getProcessId().toString();
        } else if ("name".equals(orderKey)) {
            s1 = process1.getProcessId().getLocalPart();
            s2 = process2.getProcessId().getLocalPart();
        } else if ("namespace".equals(orderKey)) {
            s1 = process1.getProcessId().getNamespaceURI();
            s2 = process2.getProcessId().getNamespaceURI();
        } else if ("version".equals(orderKey)) {
            s1 = ""+process1.getVersion();
            s2 = ""+process2.getVersion();
        } else if ("status".equals(orderKey)) {
            s1 = ""+instanceDAO1.getState();
            s2 = ""+instanceDAO2.getState();
        } else if ("started".equals(orderKey)) {
            s1 = ISO8601DateParser.format(instanceDAO1.getCreateTime());
            s2 = ISO8601DateParser.format(instanceDAO2.getCreateTime());
        } else if ("last-active".equals(orderKey)) {
            s1 = ISO8601DateParser.format(instanceDAO1.getLastActiveTime());
            s2 = ISO8601DateParser.format(instanceDAO2.getLastActiveTime());
        }
        if (ascending) return s1.compareTo(s2);
        else return s2.compareTo(s1);
    }

    private boolean equalsOrWildcardMatch(String s1, String s2) {
        if (s1 == null || s2 == null) return false;
        if (s1.equals(s2)) return true;
        if (s1.endsWith("*")) {
            if (s2.startsWith(s1.substring(0, s1.length() - 1))) return true;
        }
        if (s2.endsWith("*")) {
            if (s1.startsWith(s2.substring(0, s2.length() - 1))) return true;
        }
        return false;
    }

    public boolean dateMatch(List<String> dateFilters, Date instanceDate,  InstanceFilter filter) {
        boolean match = true;
        for (String ddf : dateFilters) {
            String isoDate = ISO8601DateParser.format(instanceDate);
            String critDate = Filter.getDateWithoutOp(ddf);
            if (ddf.startsWith("=")) {
                if (!isoDate.startsWith(critDate)) match = false;
            } else if (ddf.startsWith("<=")) {
                if (!isoDate.startsWith(critDate) && isoDate.compareTo(critDate) > 0) match = false;
            } else if (ddf.startsWith(">=")) {
                if (!isoDate.startsWith(critDate) && isoDate.compareTo(critDate) < 0) match = false;
            } else if (ddf.startsWith("<")) {
                if (isoDate.compareTo(critDate) > 0) match = false;
            } else if (ddf.startsWith(">")) {
                if (isoDate.compareTo(critDate) < 0) match = false;
            }
        }
        return match;
    }


    public ScopeDAO getScope(Long siidl) {
        for (ProcessDaoImpl process : _store.values()) {
            for (ProcessInstanceDAO instance : process._instances.values()) {
                if (instance.getScope(siidl) != null) return instance.getScope(siidl);
            }
        }
        return null;
    }


    public void insertBpelEvent(BpelEvent event, ProcessDAO processConfiguration, ProcessInstanceDAO instance) {
        _events.add(event);
    }


    public List<Date> bpelEventTimelineQuery(InstanceFilter ifilter, BpelEventFilter efilter) {
        // TODO : Provide more correct implementation:
        ArrayList<Date> dates = new ArrayList<Date>();
        CollectionsX.transform(dates, _events, new UnaryFunction<BpelEvent,Date>() {
            public Date apply(BpelEvent x) {
                return x.getTimestamp();
            }
        });
        return dates;
    }


    public List<BpelEvent> bpelEventQuery(InstanceFilter ifilter, BpelEventFilter efilter) {
        // TODO : Provide a more correct (filtering) implementation:
        return _events;
    }

    /**
     * @see org.apache.ode.bpel.dao.BpelDAOConnection#instanceQuery(String)
     */
    public Collection<ProcessInstanceDAO> instanceQuery(String expression) {
        //TODO
        throw new UnsupportedOperationException();
    }

    static void removeMessageExchange(String mexId) {
        // Cleaning up mex
        if (__log.isDebugEnabled()) __log.debug("Removing mex " + mexId + " from memory store.");
        MessageExchangeDAO mex = _mexStore.remove(mexId);
        if (mex == null)
            __log.warn("Couldn't find mex " + mexId + " for cleanup.");
        _mexAge.remove(mexId);
    }

    public void defer(final Runnable runnable) {
        _scheduler.registerSynchronizer(new Scheduler.Synchronizer() {
            public void afterCompletion(boolean success) {
            }
            public void beforeCompletion() {
                runnable.run();
            }
        });
    }
    public void onRollback(final Runnable runnable) {
        _scheduler.registerSynchronizer(new Scheduler.Synchronizer() {
            public void afterCompletion(boolean success) {
                if (!success) runnable.run();
            }
            public void beforeCompletion() {
            }
        });
    }

    public Map<Long, Collection<CorrelationSetDAO>> getCorrelationSets(Collection<ProcessInstanceDAO> instances) {
        Map<Long, Collection<CorrelationSetDAO>> map = new HashMap<Long, Collection<CorrelationSetDAO>>();
        for (ProcessInstanceDAO instance: instances) {
            Long id = instance.getInstanceId();
            Collection<CorrelationSetDAO> existing = map.get(id);
            if (existing == null) {
                existing = new ArrayList<CorrelationSetDAO>();
                map.put(id, existing);
            }
            existing.addAll(instance.getCorrelationSets());
        }
        return map;
    }

    public Collection<CorrelationSetDAO> getActiveCorrelationSets() {
        throw new UnsupportedOperationException();
    }

    public ProcessManagementDaoImpl getProcessManagement() {
        return new ProcessManagementDaoImpl();
    }
}
