package org.jcon.io;

import org.jcon.util.DataLib;
import org.jcon.util.GenLib;
import java.io.*;
import java.util.StringTokenizer;
import java.util.Vector;

// testing only
import javax.swing.JTextField;
import javax.swing.JFrame;

/**
 * This class handles Java class "text resource" management,
 * notably reading and writing files associated with classes. 
 * Replaces older methods in TextFile.
 * <p>
 * Note that "resource" is relative to the "marker" object
 * and may contain directories prepended to the fileName.
 * By using a marker object, not a class name, we preserve
 * class loader resource location.
 *
 * @author Jack Harich
 */
public class TextResource {

//---------- Private Methods -----------------------------
private Object marker;
private String resource;
static final Object mutex = new Object();

//---------- Initialization ------------------------------
public TextResource() {
}
public TextResource(Object marker, String resource) {
    this.marker = marker;

	// CMC - Must replace \ with / so the resource can be found in a jar.  
	this.resource = resource.replace('\\', '/');
}    
//---------- Properties ----------------------------------
//----- marker
public void setMarker(Object marker) {
    this.marker = marker;   
}    
public Object getMarker() {
    return marker;   
}    
//----- resource
public void setResource(String resource) {
	// CMC - Must replace \ with / so the resource can be found in a jar.  
	this.resource = resource.replace('\\', '/');
}    
public String getResource() {
    return resource;   
}    
//---------- Public Methods ------------------------------
/**
* Appends the text to the resource, creating it
* if it doesn't exist.
*/
// Better way???
public void appendString(String text) {
    if (exists()) {
        // Append
        String oldText = readString();
        writeString(oldText + text);
    } else {
        // Write first time
        writeString(text);   
    }
}
/**
* Replaces the the current contents of the file with the text.
* <p>
* The problem of TextArea carrage returns being incompatible
* with those in files is resolved by removing them and
* using println() to use the proper line seperator.
*/
public void writeString(String text) {
    String fileName = createFileName();
    PrintWriter writer = openForOutput(fileName, false);
    if (writer == null) throwFileNotFound();

    try {
        StringTokenizer tokens = new StringTokenizer(text, "\n");
        while (tokens.hasMoreTokens()) {
            writer.println(tokens.nextToken());
        } 
        writer.close();               
    } catch(Exception ex) {
        throwProblemWriting();
    }
}    
/**
* Reads the text in the resource into a String and returns
* it. Throws IllegalStateException if file not found or
* problem with read.
*/
public String readString() {
    BufferedReader reader = openForInput(true);
    if (reader == null) throwFileNotFound();
        
    // Suprisingly, initial capacity of 30000 doesn't speed up
    // 10240 slightly better for large file
    StringBuffer text = new StringBuffer();
    try {
        String line = reader.readLine();
        while (line != null) {
            text.append(line);
            text.append("\n");
            line = reader.readLine();
        }
        reader.close();
    } catch(IOException ex) {
        throwProblemReading();
    }
    return text.toString();   
}
/**
* Reads the text in the resource into a String array and 
* returns it. Throws IllegalStateException if file not
* found. The delimiterLine is an entire line.
*/
public String[] readStringArray(String delimiterLine) {
    String[] lines = DataLib.convertDelimStringToArray(
        readString(), "\n");
    
    Vector items = new Vector();
    StringBuffer item = new StringBuffer();
    boolean itemExists = false;
    for (int i = 0; i < lines.length; i++) {
        String line = lines[i];
        if (line.equals(delimiterLine)) {
            items.addElement(item.toString());
            item = new StringBuffer();
            itemExists = false;    
        } else {
            itemExists = true;
            item.append(line);
            item.append("\n");
        }        
    }
    // Awkward algorithm to get last item
    if (itemExists) items.addElement(item.toString());

    return DataLib.convertVectorToStringArray(items);      
}
/**
* Returns true if the resource is empty, false if not.
* Throws IllegalStateException if not found.
*/
public boolean isEmpty() {
    File file = new File(createFileName());
    if (! file.exists()) throwFileNotFound();
    
    return (file.length() == 0 ? true : false);
}
/**
* Returns true if the resource file exists, false if not.
*/
public boolean exists() {
    File file = new File(createFileName());
    return file.exists();
}    
/**
* Empties the resource file. Returns true for success or
* false if the file is not found or cannot be emptied.
*/
public boolean empty() {
    String fileName = createFileName();
    PrintWriter writer = openForOutput(fileName, false);
    if (writer == null) return false;

    try {
        writer.print("");
        writer.close();
        return true;
    } catch(Exception ex) {
        return false;
    }
}
/**
* Deletes the resource, which currently is a local file.
* Throws an IllegalStateException of file not found.
* Returns true for success, false for failure.
*/
public boolean delete() {
    File file = new File(createFileName());
    if (file.exists()) {
        return file.delete();
    } else {
        throwFileNotFound();
        return false;
    }
}    
//---------- Private Methods -----------------------------
private String createFileName() {
    String resourcePath = ResourceLib.getResourcePath(marker);
    return resourcePath + resource;
}    
// Returns null if problem or file not found.
private BufferedReader openForInput(boolean displayProblem) {
    
    if (marker == null) return null;
    
    InputStream inputStream = marker.getClass().getResourceAsStream(resource);

    if (inputStream == null) {
        if (displayProblem) {
            GenLib.error("TextResource.openForInput()",
                "Unable to open " + getFullName());
        }
        return null; // Crash off into the bushes....
    }
    return new BufferedReader(new InputStreamReader(inputStream));
} 
// Returns null if problem. Automatically creates if not found.
private PrintWriter openForOutput(String fileName, boolean displayProblem) {
    try {
        return new PrintWriter(
            new BufferedWriter(new FileWriter(fileName)));

    } catch(Exception ex) {
        if (displayProblem) {
            GenLib.exception("TextResource.openForOuptut()",
                "Failure on file " + fileName, ex);
        }
        return null;
    }    
}
// Returns null if marker == null
private String getClassName() {
    return (marker == null ? null : marker.getClass().getName());   
}
private String getFullName() { // For display only
  return getClassName() + "/" + resource;    
}
private void throwFileNotFound() {
    throw new IllegalStateException(
        "File not found for " + getFullName());
}   
private void throwProblemWriting() {
    throw new IllegalStateException(
        "Problem writing file for " + getFullName());
}
private void throwProblemReading() {
    throw new IllegalArgumentException(
        "Problem reading file for " + getFullName());
}    
//--- Std
private static void print(String text) {
    System.out.println("TextResource" + text);
}

} // End class
