/**************************************************************************
 OmegaT - Computer Assisted Translation (CAT) tool
          with fuzzy matching, translation memory, keyword search,
          glossaries, and translation leveraging into updated projects.

 Copyright (C) 2015 Thomas Cordonnier
               Home page: http://www.omegat.org/
               Support center: http://groups.yahoo.com/group/OmegaT/

 This file is part of OmegaT.

 OmegaT is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 OmegaT 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 **************************************************************************/

package org.omegat.core.matching.external.rmi;

import org.omegat.core.data.*;
import org.omegat.core.Core;
import org.omegat.core.CoreEvents;

import org.omegat.core.matching.external.IEntryCursor;
import org.omegat.core.matching.external.ProjectMemory;
import org.omegat.core.events.IEntryEventListener;
import org.omegat.core.events.IProjectEventListener;

import java.util.*;
import java.rmi.*;

/** 
 * A server which gives access to current project opened in the editor: <br/>
 * in the editor you wil see changes from clients and they will receive yours.
 * Usage : OmegaT [--server-port=nnnn]? --server-object=any [project]
 **/
public class GUIServer extends ProjectServer implements IEntryEventListener {

    private GUIServer() throws RemoteException {
        CoreEvents.registerEntryEventListener(this);
    }
    
    public static GUIServer open(String portStr, String object) throws Exception {
        int port = 1099; if (portStr != null) port = Integer.parseInt(portStr);
        java.rmi.registry.LocateRegistry.createRegistry(port);
        System.err.println("Listening server " + port);
        
        if (! object.startsWith("//")) if (port != 1099) object = "//localhost:" + port + "/" + object;
        GUIServer res = new GUIServer(); java.rmi.Naming.bind(object, res);
        System.err.println("Listening server object " + object);
        
        return res;
    }

    // -------------------- IProjectEventListener -------------
    
    @Override public void onProjectChanged(IProjectEventListener.PROJECT_CHANGE_TYPE eventType) {
        switch (eventType) {
        case CLOSE: case CREATE: case LOAD:
            changesFromClients.clear(); 
        }
        super.onProjectChanged(eventType);
    }
    
    // -------------------- IEntryEventListener -------------
    
    public void onNewFile(String activeFileName) {}
    
    private Set<Integer> changesFromClients = new HashSet<Integer>();
    private boolean isUpdating = false;
    
    public void onEntryActivated(SourceTextEntry newEntry) {
        if (isUpdating) return; // do not block GUI, better delay refresh
        synchronized(changesFromClients) { // also delay changes during refresh
            try {
                if (changesFromClients.size() > 0) {
                    Core.getEditor().commitAndDeactivate();
                    Core.getEditor().refreshEntries (changesFromClients);
                    Core.getEditor().activateEntry(); 
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                changesFromClients.clear(); // always clear, else changes may cummulate and slow down refresh!
            }
        }
        changesByDate.addLast (newEntry);
    }

    // ------------------ IDistantExternalMemory -------------
    
    @Override public void registerDefaultTranslation(String src, String tra) {
        SourceTextEntry ste = entries.existSource.get(src); if (ste == null) return; // do not store orphans
        PrepareTMXEntry pe = new PrepareTMXEntry(); pe.source = src; pe.translation = tra;
        Core.getProject().setTranslation(ste, pe, true, null); 
        synchronized(changesFromClients) { isUpdating = true; changesFromClients.add(ste.entryNum()); isUpdating = false; }
    }
    
    /** Register alternative translation. Parameters are split because they are not serializable **/
    @Override public void registerAltTranslation(String src, String tra, String file, String id, String path, String prev, String next) {
        SourceTextEntry ste = entries.existKeys.get(new EntryKey(file, src, id, prev, next, path)); if (ste == null) return; // do not store orphans
        PrepareTMXEntry pe = new PrepareTMXEntry(); pe.source = src; pe.translation = tra;
        Core.getProject().setTranslation(ste, pe, false, null); 
        synchronized(changesFromClients) { isUpdating = true; changesFromClients.add(ste.entryNum()); isUpdating = false; }
    }
    
}
