/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2012 Neil C Smith.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 only, as
* published by the Free Software Foundation.
*
* This code 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
* version 3 for more details.
*
* You should have received a copy of the GNU General Public License version 3
* along with this work; if not, see http://www.gnu.org/licenses/
*
*
* Please visit http://neilcsmith.net if you need additional information or
* have any questions.
*/
package net.neilcsmith.praxis.live.project;
import org.openide.filesystems.FileUtil;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import net.neilcsmith.praxis.core.syntax.Token;
import net.neilcsmith.praxis.core.syntax.Tokenizer;
import net.neilcsmith.praxis.live.project.api.ExecutionLevel;
import net.neilcsmith.praxis.live.project.api.PraxisProjectProperties;
import org.openide.filesystems.FileObject;
import static net.neilcsmith.praxis.core.syntax.Token.Type.*;
/**
*
* @author Neil C Smith (http://neilcsmith.net)
*/
class PXPReader {
final static String INCLUDE_CMD = "include";
final static String FILE_CMD = "file";
final static String BUILD_LEVEL_SWITCH = "<<<BUILD>>>";
final static String RUN_LEVEL_SWITCH = "<<<RUN>>>";
private FileObject projectDir;
private FileObject data;
private ProjectPropertiesImpl props;
private ExecutionLevel level;
private List<FileObject> buildFiles;
private List<FileObject> runFiles;
private PXPReader(FileObject projectDir,
FileObject data, ProjectPropertiesImpl props) {
this.projectDir = projectDir;
this.data = data;
this.props = props;
buildFiles = new ArrayList<FileObject>();
runFiles = new ArrayList<FileObject>();
}
private void parse() throws Exception {
Iterator<Token> tokens = new Tokenizer(loadFile(data)).iterator();
while (tokens.hasNext()) {
Token[] line = tokensToEOL(tokens);
if (line.length == 0) {
continue;
}
Token first = line[0];
switch (first.getType()) {
case PLAIN:
parseInclude(line);
break;
case COMMENT:
parseComment(line);
break;
default:
throw new IllegalArgumentException("Unexpected token");
}
}
props.setProjectFiles(ExecutionLevel.BUILD, buildFiles.toArray(new FileObject[buildFiles.size()]));
props.setProjectFiles(ExecutionLevel.RUN, runFiles.toArray(new FileObject[runFiles.size()]));
}
private String loadFile(FileObject data) throws IOException {
return data.asText();
}
private void parseComment(Token[] tokens) {
String text = tokens[0].getText();
if (text.contains(BUILD_LEVEL_SWITCH)) {
switchLevel(ExecutionLevel.BUILD);
} else if (text.contains(RUN_LEVEL_SWITCH)) {
switchLevel(ExecutionLevel.RUN);
}
}
private void switchLevel(ExecutionLevel level) {
if (level == ExecutionLevel.BUILD && this.level == ExecutionLevel.RUN) {
throw new IllegalArgumentException("Can't move level down");
}
this.level = level;
}
private void parseInclude(Token[] tokens) throws Exception {
if (! INCLUDE_CMD.equals(tokens[0].getText())) {
throw new IllegalArgumentException("Unexpected command in project file : " + tokens[0].getText());
}
if (tokens.length != 2) {
throw new IllegalArgumentException("Unexpected number of arguments in include command");
}
if (tokens[1].getType() == Token.Type.SUBCOMMAND) {
FileObject file = parseFileCommand(tokens[1].getText());
if (level == null) {
switchLevel(ExecutionLevel.RUN);
}
if (level == ExecutionLevel.BUILD) {
buildFiles.add(file);
} else {
runFiles.add(file);
}
}
}
private FileObject parseFileCommand(String command) throws Exception {
Token[] toks = tokensToEOL(new Tokenizer(command).iterator());
if (toks.length == 2 && FILE_CMD.equals(toks[0].getText())) {
URI base = FileUtil.toFile(projectDir).toURI();
URI path = base.resolve(new URI(null, null, toks[1].getText(), null));
return FileUtil.toFileObject(new File(path));
}
throw new IllegalArgumentException("Invalid file in include line : " + command);
}
private static Token[] tokensToEOL(Iterator<Token> tokens) {
List<Token> tks = new ArrayList<Token>();
while (tokens.hasNext()) {
Token t = tokens.next();
if (t.getType() == EOL) {
break;
}
tks.add(t);
}
return tks.toArray(new Token[tks.size()]);
}
static void initializeProjectProperties(FileObject projectDir,
FileObject file,
ProjectPropertiesImpl props) throws Exception {
new PXPReader(projectDir, file, props).parse();
}
}