package org.jcon.param;

import org.jcon.util.GenLib;
import org.jcon.util.BenchMark;
import org.jcon.io.ResourceLib;
import org.jcon.io.TextResource;
import java.io.IOException;

/**
 * A ParamStore implementation that uses the class resource
 * mechanism built into Java. This is an extremely lightweight
 * approach, since no complex storage subsystem or third
 * party software such as a database is needed.
 * <p>
 * Params are stored and treated
 * as class resource files. This allows loading via class
 * loader resources, which encapsulates the parameter
 * file with the class and allows internet deployment.
 * <p>
 * This class may also be used for simple Param use, such
 * as init files and test data.
 * <p>
 * An example of reading a Param is: <pre>
 *   ParamAccessor accessor = new ParamAccessor();
 *   accessor.setMarkerClass(new AnyClass());
 *   accessor.setResourceName("atsdr/schema/system/UserSys.parex");
 *   Param param = new ParamStoreResource().readParam(accessor);
 * </pre>
 * @author Jack Harich
 */
public class ParamStoreResource implements ParamStore {
    
//---------- Private Fields ------------------------------
private TextResource textResource = new TextResource();    

//---------- ParamStore Implementation -------------------
/**
 * Creates and returns a Param using the ParamAccessor.
 */
public Param readParam(ParamAccessor accessor) {
    //BenchMark.getTimePoint(0);

   BenchMark.endStep("ParamStoreResource pre readParam()");

    // Read text from file
    textResource.setMarker(accessor.getMarkerClass());
    textResource.setResource(accessor.getResourceName());
    String text = textResource.readString();
    // ***String text = readText(instance, resourceName);
    BenchMark.endStep("ParamStoreResource Read File");

    // Create param from text
    Param param = ParamConverter.toParam(text); // Sets text
    BenchMark.endStep("ParamStoreResource Convert");

    // Configure param
    param.getAccessor().setMarkerClass(accessor.getMarkerClass());
    param.getAccessor().setResourceName(accessor.getResourceName());
    return param;
}
/**
 * Writes the param using its ParamAccessor data. If newText
 * is not null then the param is written with the newText
 * and the param is updated. Returns true for success,
 * false for failure.
 */
public boolean writeParam(Param param, String newText) {
try {
    ParamAccessor accessor = param.getAccessor();
    // Get relative fileName
    String path = ResourceLib.getResourcePath(accessor.getMarkerClass());
    String fileName = path + accessor.getResourceName();
    // Prepare textResource
    textResource.setMarker(accessor.getMarkerClass());
    textResource.setResource(accessor.getResourceName());
    // Write
    String text;
    text = (newText == null ? param.buildText() : newText);
    textResource.writeString(text);
    // Update param if newText provided
    if (newText != null) {
        // Not efficient, but simple and assertive
        Param newParam = readParam(param.getAccessor());
        // The following line does nothing if not param driven
        newParam.setParamDriven(param.getParamDriven());
        
        param.copy(newParam);
    }
    return true;
    
} catch(Exception ex) { 
    GenLib.exception("ParamStoreResource.writeParam()",
        "Cannot write param.", ex);   
    return false;
}
} // End method

//---------- Public Methods ------------------------------
/**
* A convenience method for low level Param use. This is the
* same as readParam(Accessor). Returns null if failure.
*/
public static Param createParam(String markerClassName, 
									String resourceName) {
									
	Object instance = GenLib.createInstance(markerClassName);
	if (instance == null) return null;
	
    ParamAccessor accessor = new ParamAccessor();
    accessor.setMarkerClass(instance);
    accessor.setResourceName(resourceName);    

    return new ParamStoreResource().readParam(accessor);    
}
/**
* Another convenience method for low level Param use. This is the
* same as readParam(Accessor). Returns null if failure.
*/
public static Param createParam(Object markerClassInstance, 
                                    String resourceName) {
                                       
    ParamAccessor accessor = new ParamAccessor();
    accessor.setMarkerClass(markerClassInstance);
    accessor.setResourceName(resourceName);    

    return new ParamStoreResource().readParam(accessor);    
}
//---------- Private Methods -----------------------------
// This is old but interesting work

/** private String readText(Object instance,
            String resourceName) {
    TextFile file = TextFile.createForRead(instance,
        resourceName);
    if (file == null) {
        GenLib.error("ParamStoreResource.readResourceParam()",
            "Cannot read TextFile for instance " +
            instance.getClass().getName() +
            ", resourceName " + resourceName);
        return null;
    }
    // Buffer much faster than concatenation
    // Suprisingly, initial capacity of 30000 doesn't speed up
    // 10240 slightly better for large file
    StringBuffer text = new StringBuffer();
    String line = file.readLine();
    while (line != null) {
       text.append(line);
       text.append("\n");
       line = file.readLine();
    }
    file.close();
    return text.toString();
} */
//--- Std
private static void print(String text) {
    System.out.println("ParamStoreResource" + text);
}

} // End class
