package com.iambookmaster.client.paragraph;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import com.iambookmaster.client.beans.Greeting;
import com.iambookmaster.client.beans.Modificator;
import com.iambookmaster.client.beans.ObjectBean;
import com.iambookmaster.client.beans.Paragraph;
import com.iambookmaster.client.beans.ParagraphConnection;
import com.iambookmaster.client.exceptions.TimeoutException;
import com.iambookmaster.client.locale.AppLocale;
import com.iambookmaster.client.model.Model;
import com.iambookmaster.client.model.Model.FullParagraphDescriptonBuilder;
import com.iambookmaster.client.model.ParagraphDescriptionLinkProvider;
public class BookCreator {
protected Model model;
public BookCreator(Model model) {
this.model = model;
}
public String createText(boolean reExport,BookCreatorListener listener) throws TimeoutException {
if (reExport) {
//paragraph numbers already set
Paragraph[] book = validateBookNumbers(listener);
if (book==null) {
return null;
} else {
TextBookDecrator decrator = new TextBookDecrator(model,AppLocale.getAppConstants(),AppLocale.getAppMessages());
// BookDecorator decrator = new URQBookDecrator(model,AppLocale.getAppConstants(),AppLocale.getAppMessages());
createText(book, listener, decrator);
return decrator.toText();
}
} else if (model.getSettings().getMinimalSeparation()==0) {
//no separation at all
ArrayList<Paragraph> all = model.getParagraphs();
int size = all.size();
for (int i = 0; i < size; i++) {
all.get(i).setNumber(i+1);
}
Paragraph[] book = validateBookNumbers(listener);
if (book==null) {
return null;
} else {
BookDecorator decrator = new TextBookDecrator(model,AppLocale.getAppConstants(),AppLocale.getAppMessages());
createText(book, listener, decrator);
return decrator.toString();
}
} else {
listener.noSupported();
return null;
}
}
public Paragraph[] validateBookNumbers(BookCreatorListener listener) {
ArrayList<Paragraph> all = model.getParagraphs();
Paragraph[] book = new Paragraph[all.size()];
int max = all.size();
boolean critical=false;
//validation, step 1
for (Paragraph paragraph:all) {
int num = paragraph.getNumber();
int numZero = num-1;
if (num<1) {
//number is not set
paragraph.setNumber(0);
listener.numberNotSet(paragraph);
critical = true;
} else if (num>max) {
listener.numberTooLarge(paragraph,max);
critical = true;
} else if (book[numZero] != null){
listener.numbersDuplicated(paragraph,book[numZero]);
critical = true;
} else {
book[numZero] = paragraph;
}
for (ObjectBean bean : paragraph.getGotObjects()) {
if (bean.getKey()==0) {
listener.numberNotSet(bean);
critical = true;
}
}
}
//validation, step 2
if (model.getSettings().isHiddenUsingObjects()) {
//check object numbers
ArrayList<ParagraphConnection> allConnections = model.getParagraphConnections();
for (ParagraphConnection connection : allConnections) {
if (connection.getObject() != null) {
if (connection.getObject().getKey()==0) {
listener.numberNotSet(connection.getObject());
critical = true;
} else if (connection.getFrom().getNumber()+connection.getObject().getKey() != connection.getTo().getNumber()) {
//wrong key, directs us to wrong number
listener.wrongObjectSecretKey(connection);
critical = true;
}
}
}
}
if (critical) {
return null;
} else {
return book;
}
}
public void createText(Paragraph[] book, final BookCreatorListener listener, final BookDecorator decrator) {
//update paragraph number
for (int i = 0; i < book.length; i++) {
book[i].setNumber(i+1);
}
ArrayList<Greeting> greetings = model.getSettings().getGreetings();
if (greetings != null) {
decrator.startGreeting();
for (Greeting greeting:greetings) {
decrator.addGreeting(greeting);
}
decrator.endGreeting();
}
HashMap<Paragraph, ArrayList<ParagraphConnection>> links = new HashMap<Paragraph, ArrayList<ParagraphConnection>>(model.getParagraphs().size());
HashMap<Paragraph, ArrayList<ParagraphConnection>> inLinks = new HashMap<Paragraph, ArrayList<ParagraphConnection>>(model.getParagraphs().size());
ArrayList<ParagraphConnection> connections = model.getParagraphConnections();
final HashMap<Modificator,Paragraph> absModificators = new HashMap<Modificator, Paragraph>();
for (int i = 0; i < connections.size(); i++) {
ParagraphConnection connection = connections.get(i);
addLink(links,connection.getFrom(),connection);
addLink(inLinks, connection.getTo(), connection);
if (connection.isBothDirections()) {
addLink(links,connection.getTo(),connection);
addLink(inLinks, connection.getFrom(), connection);
}
if (connection.getType()==ParagraphConnection.TYPE_MODIFICATOR) {
if (connection.getModificator()==null) {
listener.algorithmError(BookCreatorListener.ERROR_MODIFICATOR_NOT_SET);
} else if (connection.getModificator().isAbsolute()){
if (absModificators.containsKey(connection.getModificator())) {
if (absModificators.get(connection.getModificator()) != connection.getTo()) {
listener.algorithmError(BookCreatorListener.ERROR_NON_UNIQUE_ABSOLUTE_MODIFICATOR);
}
} else {
absModificators.put(connection.getModificator(),connection.getTo());
}
}
}
}
final HashSet<Paragraph> used = new HashSet<Paragraph>(book.length);
for (int i = 0; i < book.length; i++) {
if (book[i]==null) {
listener.algorithmError(0);
}
if (used.contains(book[i])) {
listener.algorithmError(1);
}
if (book[i]==model.getStartParagraph()) {
//start
decrator.setStartParagraph(book[i]);
}
used.add(book[i]);
}
FullParagraphDescriptonBuilder builder = model.getFullParagraphDescriptonBuilder();
builder.setPlayerMode(decrator.isPlayerMode());
builder.setParagraphParsingHandler(decrator.getParagraphParsingHandler());
builder.setCheckSecretKeys(true);
builder.setEmptyConditionIsError(model.getSettings().isHiddenUsingObjects()==false);
builder.setLinkProvider(new ParagraphDescriptionLinkProvider() {
public String getLinkTo(Paragraph from, Paragraph to, ParagraphConnection connection) {
if (used.contains(to)) {
if (connection.getType()==ParagraphConnection.TYPE_MODIFICATOR && connection.getModificator().isAbsolute() && decrator.isHideAbsoluteModificators()) {
//nothing, abs. modificator has own code
return "";
} else {
return decrator.decorateNumber(to.getNumber(),from,to,connection);
}
} else {
listener.algorithmError(BookCreatorListener.ERROR_PARAGRAPH_NUMBER_NOT_SET);
return "";
}
}
public String getModificatorValue(Modificator modificator) {
Paragraph paragraph = absModificators.get(modificator);
if (paragraph==null) {
return null;
} else {
return String.valueOf(paragraph.getNumber());
}
}
});
decrator.startBook();
for (int i = 0; i < book.length; i++) {
connections = links.get(book[i]);
ArrayList<ParagraphConnection> inConnections = inLinks.get(book[i]);
decrator.appendParagraph(book[i].getNumber(),builder.getFullParagraphDescripton(book[i], null, connections),book[i],connections,inConnections);
}
decrator.endBook();
model.refreshParagraphs();
}
private void addLink(HashMap<Paragraph, ArrayList<ParagraphConnection>> links, Paragraph from, ParagraphConnection to) {
ArrayList<ParagraphConnection> list = links.get(from);
if (list==null) {
list = new ArrayList<ParagraphConnection>();
links.put(from, list);
}
list.add(to);
}
}