/*
* JETERS – Java Extensible Text Replacement System
* Copyright (C) 2006–2008 Tobias Knerr
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
*/
package net.sf.jeters.components;
import net.sf.jeters.util.*;
import net.sf.jeters.componentInterface.UIComponent;
import net.sf.jeters.componentInterface.dataStructs.NamedDataNotAvailableException;
import net.sf.jeters.componentInterface.dataStructs.NamedDataSet;
import net.sf.jeters.componentInterface.dataStructs.UIRequest;
import net.sf.jeters.componentInterface.dataStructs.UIRequest_Boolean;
import net.sf.jeters.componentInterface.dataStructs.UIRequest_Float;
import net.sf.jeters.componentInterface.dataStructs.UIRequest_Integer;
import net.sf.jeters.componentInterface.dataStructs.UIRequest_Selection;
import net.sf.jeters.configuration.Conf;
import java.util.Vector;
import java.io.*;
/**
* the default implementation of a (very basic) command line UI component for JETERS.
* For a graphical UI, see DefaultGUI.
*
* @author Tobias Knerr
*/
public class DefaultCLI extends AssistedTranslatable
implements UIComponent {
private final int UNCHANGED_PARTS_PADDING = 10;
//the CLI's settings
@Conf
private boolean showHelpTexts = false;
private static String[] markChanges(String textVersion1, String textVersion2, String beginChangeMarker, String endChangeMarker){
String resultStrings[] = new String[2];
int lengthTextVersion1 = (textVersion1!=null)?(textVersion1.length()):(0);
int lengthTextVersion2 = (textVersion2!=null)?(textVersion2.length()):(0);
//check if the strings contain content
if( lengthTextVersion1 == 0 || lengthTextVersion2 == 0 ){
if( lengthTextVersion1 == 0 ){
if( lengthTextVersion2 == 0 ){
resultStrings[0] = beginChangeMarker + endChangeMarker;
resultStrings[1] = beginChangeMarker + endChangeMarker;
}
else{ //lengthTextVersion1 == 0 && lengthTextVersion2 != 0
resultStrings[0] = beginChangeMarker + endChangeMarker;
resultStrings[1] = beginChangeMarker + textVersion2 + endChangeMarker;
}
}
else{ //lengthTextVersion1 != 0 && lengthTextVersion2 == 0
resultStrings[0] = beginChangeMarker + textVersion1 + endChangeMarker;
resultStrings[1] = beginChangeMarker + endChangeMarker;
}
}
else{
//Split textVersion1 into words and separating strings (whitespace or |)
//result of the following lines of code is a Vector with Strings containing the "words" (every sequence of characters not interrupted by whitespace or |) and another Vector with Strings containing the characters between the words
Vector<String> stringsVersion1 = new Vector<String>();
boolean firstStringIsWordVersion1 = !( ( Character.isWhitespace(textVersion1.charAt(0)) ) || ( textVersion1.charAt(0) == '|' ) );
boolean inWord = firstStringIsWordVersion1;
String nextString = new String();
for(int charNumber = 0; charNumber < lengthTextVersion1; ++ charNumber ){
Character c = textVersion1.charAt(charNumber);
if( Character.isWhitespace(c) || c == '|' ){
if( inWord ){
stringsVersion1.add(nextString);
nextString = new String();
inWord = false;
}
}
else if( !inWord ){
stringsVersion1.add(nextString);
nextString = new String();
inWord = true;
}
nextString += c;
}
stringsVersion1.add(nextString);
//Split textVersion2 into words (separated by whitespace or |)
//the same as above
Vector<String> stringsVersion2 = new Vector<String>();
boolean firstStringIsWordVersion2 = !( ( Character.isWhitespace(textVersion2.charAt(0)) ) || ( textVersion2.charAt(0) == '|' ) );
inWord = firstStringIsWordVersion2;
nextString = new String();
for(int charNumber = 0; charNumber < lengthTextVersion2; ++ charNumber ){
Character c = textVersion2.charAt(charNumber);
if( Character.isWhitespace(c) || c == '|' ){
if( inWord ){
stringsVersion2.add(nextString);
nextString = new String();
inWord = false;
}
}
else if( !inWord ){
stringsVersion2.add(nextString);
nextString = new String();
inWord = true;
}
nextString += c;
}
stringsVersion2.add(nextString);
//compare the words of version 1 with those of version 2
int numberStringsVersion1 = stringsVersion1.size();
int numberStringsVersion2 = stringsVersion2.size();
boolean unchangedVersion1[] = new boolean[numberStringsVersion1];
for( int i = 0; i < numberStringsVersion1; ++ i ){ unchangedVersion1[i] = false; }
boolean unchangedVersion2[] = new boolean[numberStringsVersion2];
for( int i = 0; i < numberStringsVersion2; ++ i ){ unchangedVersion2[i] = false; }
int indexVersion1 = firstStringIsWordVersion1 ? 0 : 1;
int indexVersion2 = 0;
while( indexVersion1 < numberStringsVersion1 && indexVersion2 < numberStringsVersion2 ){
boolean wordFoundInVersion2Strings = false;
int checkedIndexVersion2 = indexVersion2;
while( !wordFoundInVersion2Strings && checkedIndexVersion2 < numberStringsVersion2 ){
if( stringsVersion1.get(indexVersion1).compareTo(stringsVersion2.get(checkedIndexVersion2)) == 0 ){
wordFoundInVersion2Strings = true;
unchangedVersion1[indexVersion1] = true;
unchangedVersion2[checkedIndexVersion2] = true;
//also check the space before the matching words
/*++ TODO: after, too??? what's about a space at the end of the text – it won't be checked at all! ++*/
if( indexVersion1 > 0 && checkedIndexVersion2 > 0 && stringsVersion1.get(indexVersion1-1).compareTo(stringsVersion2.get(checkedIndexVersion2-1)) == 0 ){
unchangedVersion1[indexVersion1-1] = true;
unchangedVersion2[checkedIndexVersion2-1] = true;
}
}
checkedIndexVersion2 += 1;
}
if( wordFoundInVersion2Strings ){ indexVersion2 = checkedIndexVersion2; }
indexVersion1 += 2;
}
//recombine the strings, but add markers for changes
boolean lastStringWasUnchanged = true;
resultStrings[0] = new String();
for( indexVersion1 = 0; indexVersion1 < numberStringsVersion1; ++ indexVersion1 ){
if( !unchangedVersion1[indexVersion1] && lastStringWasUnchanged ){
resultStrings[0] += beginChangeMarker;
lastStringWasUnchanged = false;
}
else if ( unchangedVersion1[indexVersion1] && !lastStringWasUnchanged ){
resultStrings[0] += endChangeMarker;
lastStringWasUnchanged = true;
}
resultStrings[0] += stringsVersion1.get(indexVersion1);
}
if( !lastStringWasUnchanged ){ resultStrings[0] += endChangeMarker; }
//recombining – the same for version 2
lastStringWasUnchanged = true;
resultStrings[1] = new String();
for( indexVersion2 = 0; indexVersion2 < numberStringsVersion2; ++ indexVersion2 ){
if( !unchangedVersion2[indexVersion2] && lastStringWasUnchanged ){
resultStrings[1] += beginChangeMarker;
lastStringWasUnchanged = false;
}
else if ( unchangedVersion2[indexVersion2] && !lastStringWasUnchanged ){
resultStrings[1] += endChangeMarker;
lastStringWasUnchanged = true;
}
resultStrings[1] += stringsVersion2.get(indexVersion2);
}
if( !lastStringWasUnchanged ){ resultStrings[1] += endChangeMarker; }
}
return resultStrings;
}
public String confirmChanges(String label, String oldVersion, String newVersion, String descriptionOfChanges, boolean allowCancel){
if( newVersion.compareTo(oldVersion) == 0 || descriptionOfChanges.compareTo("") == 0 ){
return newVersion;
}
else{
String cleanedStrings[];
cleanedStrings = StringDiffHelper.removeEqualSentences(
oldVersion, newVersion, UNCHANGED_PARTS_PADDING);
cleanedStrings = markChanges(cleanedStrings[0],cleanedStrings[1],"⋙","⋘");
System.out.println("\nvor der Korrektur:\n");
System.out.println(cleanedStrings[0]);
System.out.println("\nnach der Korrektur:\n");
System.out.println(cleanedStrings[1]);
System.out.println("\nvorgenommene Änderungen:\n");
System.out.println(descriptionOfChanges);
UIRequest requestArray[] = { new UIRequest_Boolean("confirmation","\nÄnderungen übernehmen?","Bei „ja“ werden alle(!) Änderungen in diesem Textabschnitt übernommen.") };
NamedDataSet reply = this.request(requestArray);
Boolean newVersionAccepted = false;
try{
newVersionAccepted = reply.get("confirmation");
} catch( NamedDataNotAvailableException ndnae ){ /* newVersionAccepted remains false */ }
return (newVersionAccepted)?(newVersion):(oldVersion);
}
}
public NamedDataSet request(UIRequest... requests){
NamedDataSet reply = new NamedDataSet();
for( UIRequest request : requests ){
//output request
System.out.println(request.label);
if( request.getType() == UIRequest.Type.Request_Boolean ){
output("[y]es or [n]o");
}
else if( request.getType() == UIRequest.Type.Request_Selection ){
for( int possibilityIndex = 0; possibilityIndex < ((UIRequest_Selection)request).selectionNames.length; ++ possibilityIndex ){
output(String.valueOf(possibilityIndex) + ": " + ((UIRequest_Selection)request).selectionNames[possibilityIndex]);
}
}
if( showHelpTexts && !request.help.equals("") ){ output("explanation: " + request.help); }
//get answer from System input stream
if( request.getType() != UIRequest.Type.Request_Output ){
try{
boolean requestAnswered = false;
do{
//create String from inputs
BufferedInputStream keyboardInputStream = new BufferedInputStream(System.in);
String input = new String();
char readChar = (char)keyboardInputStream.read();
while( readChar != '\n' ){
input += readChar;
readChar = (char)keyboardInputStream.read();
}
if( input.length() > 0 ){
//interprete input depending on request type
switch( request.getType() ){
case Request_Boolean:
if( input.charAt(0) == 'y' ){
reply.add(request.name,true);
requestAnswered = true;
}
else if( input.charAt(0) == 'n' ){
reply.add(request.name,false);
requestAnswered = true;
}
else{
output("answer must be y or n" );
}
break;
case Request_String:
reply.add(request.name,input);
requestAnswered = true;
break;
case Request_Integer:
try{
int inputInt = Integer.parseInt(input);
if( inputInt >= ((UIRequest_Integer)request).range_min && inputInt <= ((UIRequest_Integer)request).range_max ){
reply.add(request.name,inputInt);
requestAnswered = true;
}
else{
output("Value not in range [" + String.valueOf(((UIRequest_Integer)request).range_min) + ";" + String.valueOf(((UIRequest_Integer)request).range_max) + "]!" );
}
}
catch( NumberFormatException nfe ){
output("Not a valid integer!");
}
break;
case Request_Float:
try{
float inputFloat = Float.parseFloat(input);
if( inputFloat >= ((UIRequest_Float)request).range_min && inputFloat <= ((UIRequest_Float)request).range_max ){
reply.add(request.name,inputFloat);
requestAnswered = true;
}
else{
output("Value not in range [" + String.valueOf(((UIRequest_Float)request).range_min) + ";" + String.valueOf(((UIRequest_Float)request).range_max) + "]!" );
}
}
catch( NumberFormatException nfe ){
output("Not a valid floating point value!");
}
break;
case Request_Selection:
try{
int inputInt = Integer.parseInt(input);
if( inputInt >= 0 && inputInt < ((UIRequest_Selection)request).selectionNames.length ){
reply.add(request.name,inputInt);
requestAnswered = true;
}
else{
output("Wrong value!" );
}
}
catch( NumberFormatException nfe ){
output("Not a valid integer! Enter one of the numbers listed before the options!");
}
break;
}
}
} while( !requestAnswered );
}
catch(IOException ioe){
output( "Error getting keyboard input: " + ioe.toString() + "\nVerwerfe Änderungen an diesem Absatz.");
}
}
}
return reply;
}
public void output(String message){
System.out.println(message);
}
}