package org.jcon.core.std;

import org.jcon.core.Cell;
import org.jcon.core.CellReplicator;
import org.jcon.core.Part;
import org.jcon.core.Replicable;
import org.jcon.core.WorkerWrapper;

import java.util.Vector;

/**
* This class is the standard CellReplicator. For
* documentation see CellReplicator for now. This is a
* "core service part" because it's reusable by different
* containers if single threaded.
* <p>
* NOTE - We have since noticed a potential simplification
* for the CellReplicator. The setCorePartNames() can be
* dropped. The logic in replicateCell() can simply check
* all parts in the fromCell, replicating only those that
* are core, non-service, non-container parts. 
*
* @author Jack Harich
*/
public class CellReplicatorStd implements CellReplicator {

//---------- Protected Fields ----------------------------
protected Vector corePartNames;

//---------- CellReplicator Implementation ---------------
public void setCorePartNames(Vector names) {
    corePartNames = names;
}
public Cell replicateCell(Cell fromCell) {

    if (fromCell == null) throw new IllegalArgumentException(
        "The fromCell cannot be null.");

    Cell newCell = new CellStd();
    newCell.setCore(true);
    newCell.setContainer(true);
    
    // For each core part name possibly add to newCell
    // This is done by part replication, not creation
    for (int i = 0; i < corePartNames.size(); i++) {
        String name = (String)corePartNames.elementAt(i);
        replicatePart(newCell, fromCell, name);
    }
    newCell.setParent(fromCell);
    newCell.initCell();
    
    return newCell;
}
//---------- Protected Methods ---------------------------
/**
* Adds a core non-service part to newCell. We use a
* the getPart() technique to support custom core parts
* per cell, instead of simply keeping a list of the
* root core parts. We don't use findPart because the part
* needed should be local.
*/
protected void replicatePart(
        Cell newCell, Cell fromCell, String name) {
        
    // Note findPart() works but is careless
    Part part = fromCell.getPart(name);
    
    // Replicate only core non-service non-container parts
    if (! part.isCore()) return;
    if (part.isService()) return;
    if (part.isContainer()) return;
    
    // Replicate part, add to newCell
    
    // Clone wrapper. Gee is this awkward!
    WorkerWrapper oldWrapper = (WorkerWrapper)part;
    WorkerWrapper newWrapper;
    try {
        newWrapper = (WorkerWrapper)oldWrapper.clone();
        
    } catch(CloneNotSupportedException ex) {
        throw new IllegalArgumentException(
        "Cannot clone WorkerWrapper named " + oldWrapper.getName() +
        " since not cloneable.");
    }
    // All non-service core parts must be Replicable
    // Use this to set a new instance
    // Can getWorker() from old or new, doesn't matter
    Replicable rep = (Replicable)newWrapper.getWorker();
    Object instance = rep.replicate();
    newWrapper.setWorker(instance);
    newWrapper.setVirtual(true); // Since not created from DK or hard code
    
    // TODO BUG - Need to setCell(Cell) is some. Maybe can
    // use CoreCellUser interface with setCell(Cell).
    
    // Done, add to newCell
    newCell.addPart(newWrapper);        
}    
//--- Std ---------
private static void print(String text) {
    System.out.println("CellReplicatorStd" + text);
}

} // End class