]> gerrit.simantics Code Review - simantics/sysdyn.git/commitdiff
Add missing features to vensim import, it is now feature complete but still needs...
authorjkauttio <jkauttio@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Fri, 25 Apr 2014 12:55:30 +0000 (12:55 +0000)
committerjkauttio <jkauttio@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Fri, 25 Apr 2014 12:55:30 +0000 (12:55 +0000)
refs #2924

git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/branches@29353 ac1ea38d-2e2b-0410-8846-a27921b304fc

dev-jkauttio/org.simantics.sysdyn/src/org/simantics/sysdyn/modelImport/MdlParser.java
dev-jkauttio/org.simantics.sysdyn/src/org/simantics/sysdyn/modelImport/MdlUtil.java
dev-jkauttio/org.simantics.sysdyn/src/org/simantics/sysdyn/modelImport/mdl/Lookup.java
dev-jkauttio/org.simantics.sysdyn/src/org/simantics/sysdyn/modelImport/mdl/SketchComment.java
dev-jkauttio/org.simantics.sysdyn/src/org/simantics/sysdyn/modelImport/mdl/SketchValve.java
dev-jkauttio/org.simantics.sysdyn/src/org/simantics/sysdyn/modelImport/mdl/SubscriptVariable.java
dev-jkauttio/org.simantics.sysdyn/src/org/simantics/sysdyn/modelImport/mdl/Variable.java
dev-jkauttio/org.simantics.sysdyn/src/org/simantics/sysdyn/modelImport/model/Model.java
dev-jkauttio/org.simantics.sysdyn/src/org/simantics/sysdyn/modelImport/model/expression/LookupExpression.java
dev-jkauttio/org.simantics.sysdyn/src/org/simantics/sysdyn/modelImport/model/support/Function.java
dev-jkauttio/org.simantics.sysdyn/src/org/simantics/sysdyn/modelica/ModelicaWriter.java

index 2d51eeef219d0a0fbcf3b749d932242d4c7afb3b..b60deac540107ee70ca4f98b549511e2eeed820c 100644 (file)
@@ -14,12 +14,7 @@ package org.simantics.sysdyn.modelImport;
 import java.io.BufferedReader;\r
 import java.io.File;\r
 import java.io.FileInputStream;\r
-import java.io.IOException;\r
 import java.io.InputStreamReader;\r
-import java.util.ArrayList;\r
-import java.util.HashMap;\r
-import java.util.regex.Matcher;\r
-import java.util.regex.Pattern;\r
 \r
 import org.simantics.sysdyn.modelImport.mdl.Declaration;\r
 import org.simantics.sysdyn.modelImport.mdl.Lookup;\r
@@ -27,7 +22,6 @@ import org.simantics.sysdyn.modelImport.mdl.MdlModel;
 import org.simantics.sysdyn.modelImport.mdl.Sketch;\r
 import org.simantics.sysdyn.modelImport.mdl.SketchComment;\r
 import org.simantics.sysdyn.modelImport.mdl.SketchConnection;\r
-import org.simantics.sysdyn.modelImport.mdl.SketchElement;\r
 import org.simantics.sysdyn.modelImport.mdl.SketchObject;\r
 import org.simantics.sysdyn.modelImport.mdl.SketchValve;\r
 import org.simantics.sysdyn.modelImport.mdl.SketchVariable;\r
@@ -35,18 +29,11 @@ import org.simantics.sysdyn.modelImport.mdl.Subscript;
 import org.simantics.sysdyn.modelImport.mdl.SubscriptVariable;\r
 import org.simantics.sysdyn.modelImport.mdl.Variable;\r
 import org.simantics.sysdyn.modelImport.model.Model;\r
-import org.simantics.sysdyn.modelImport.model.element.Auxiliary;\r
-import org.simantics.sysdyn.modelImport.model.element.Cloud;\r
-import org.simantics.sysdyn.modelImport.model.element.Comment;\r
 import org.simantics.sysdyn.modelImport.model.element.Connection;\r
 import org.simantics.sysdyn.modelImport.model.element.ModelVariable;\r
 import org.simantics.sysdyn.modelImport.model.element.Symbol;\r
 import org.simantics.sysdyn.modelImport.model.element.Shadow;\r
-import org.simantics.sysdyn.modelImport.model.element.Stock;\r
 import org.simantics.sysdyn.modelImport.model.element.Valve;\r
-import org.simantics.sysdyn.modelImport.model.expression.IntegralExpression;\r
-import org.simantics.sysdyn.modelImport.model.expression.NormalExpression;\r
-import org.simantics.sysdyn.modelImport.model.support.Enumeration;\r
 \r
 public class MdlParser {\r
 \r
@@ -70,12 +57,12 @@ public class MdlParser {
                double offset = 0;\r
 \r
                for (Subscript subscript : mdl.getAllSubscripts()) {\r
-                       System.err.println("added subscript "+subscript.getName()+" "+subscript.isEquivalent());\r
-                       model.addEnumeration(subscript.getEnumeration(mdl));\r
+                       if (!subscript.isEquivalent())\r
+                               model.addEnumeration(subscript.getEnumeration(mdl));\r
                }\r
                \r
                for (Lookup lookup : mdl.getAllLookups()) {\r
-                       //model.addFunction(lookup.getFunction());\r
+                       model.addFunction(lookup.getFunction());\r
                }\r
                \r
                try {\r
index cdf019de1ed0f5a3a4a3be13ec61fc190c7b1656..b3546407c80ecc934675d8846b1168820eb30c5d 100644 (file)
@@ -5,6 +5,7 @@ import java.util.List;
 import java.util.regex.Matcher;\r
 import java.util.regex.Pattern;\r
 \r
+import org.simantics.sysdyn.modelImport.mdl.Lookup;\r
 import org.simantics.sysdyn.modelImport.mdl.MdlModel;\r
 \r
 public class MdlUtil {\r
@@ -39,25 +40,25 @@ public class MdlUtil {
                        "("+BASIC_NAME+")\\[("+BASIC_NAME+"\\!?(?:,"+BASIC_NAME+"\\!?)*)\\]";\r
        // matches a vensim function (basic name followed by an open parenthesis)\r
        public static final String FUNCTION =\r
-                       "([A-Za-z]\\w*(?:\\s+\\w+)*)\\s*\\(";\r
+                       "("+BASIC_NAME+")\\s*\\(";\r
        \r
        public static String normalize(String str) {\r
                // start by removing all tabs from the string, not really necessary \r
                // but does make the equation cleaner\r
                str = str.replaceAll("\t", "");\r
 \r
-               // inline operations could be removed here if it can be done reliablty\r
-               \r
                // normalize functions\r
                str = normalizeFunctions(str);\r
                // normalize variables\r
                str = normalizeVariables(str);\r
+               \r
+               // replace inline operations\r
+               str = str.replaceAll(":AND:", " and ");\r
+               str = str.replaceAll(":OR:", " or ");\r
 \r
                return str;\r
        }\r
        \r
-       // construct a replacement string from expression where each variable\r
-       // name is normalized to a sysdyn-friendly format\r
        private static String normalizeVariables(String expression) {\r
                StringBuilder result = new StringBuilder();\r
                int offset = 0;\r
@@ -99,8 +100,6 @@ public class MdlUtil {
                return result.toString();\r
        }\r
        \r
-       // construct a replacement string from expression where each variable\r
-       // name is normalized to a sysdyn-friendly format\r
        private static String normalizeFunctions(String expression) {\r
                StringBuilder result = new StringBuilder();\r
                int offset = 0;\r
@@ -111,16 +110,26 @@ public class MdlUtil {
 \r
                        String function = matcher.group(1);\r
                        \r
-                       if (function.equalsIgnoreCase("IF THEN ELSE")) {\r
-                               result.append("IFTHENELSE");\r
+                       if (function.equalsIgnoreCase("sum")) {\r
+                               // vensim "sum" is similar to modelica "sum" if operations \r
+                               // are replaced with dot-operations (e.g. * with .*) inside\r
+                               // the parameters\r
+                               result.append("sum(");\r
+                               int closing = expression.indexOf(')', matcher.end());\r
+                               String parameters = expression.substring(matcher.end(), closing);\r
+                               parameters = parameters.replaceAll("\\*", ".*");\r
+                               result.append(parameters);\r
+                               offset = closing;\r
+                       }\r
+                       else if (function.equalsIgnoreCase("if then else")) {\r
+                               result.append("IFTHENELSE(");\r
+                               offset = matcher.end();\r
                        }\r
                        else {\r
                                // this will also capitalize lookups, is this ok?\r
-                               result.append(function.toUpperCase());\r
+                               result.append(function.toUpperCase()+"(");\r
+                               offset = matcher.end();\r
                        }\r
-                       result.append('(');\r
-\r
-                       offset = matcher.end();\r
                }\r
                if (offset < expression.length()) {\r
                        result.append(expression.substring(offset));\r
@@ -129,11 +138,14 @@ public class MdlUtil {
                return result.toString();\r
        }\r
        \r
-       public static String expandIterations(String expression, MdlModel mdl) {\r
-               if (!expression.contains("[")) {\r
-                       return expression;\r
-               }\r
+       public static String finalize(String expression, MdlModel mdl) {\r
+               expression = expandIterations(expression, mdl);\r
+               expression = renameLookups(expression, mdl);\r
                \r
+               return expression;\r
+       }\r
+       \r
+       private static String expandIterations(String expression, MdlModel mdl) {\r
                StringBuilder result = new StringBuilder();\r
                int offset = 0;\r
 \r
@@ -177,12 +189,37 @@ public class MdlUtil {
                return result.toString();\r
        }\r
        \r
+       private static String renameLookups(String expression, MdlModel mdl) {\r
+               StringBuilder result = new StringBuilder();\r
+               int offset = 0;\r
+\r
+               Matcher matcher = Pattern.compile(FUNCTION).matcher(expression);\r
+               while (matcher.find()) {\r
+                       result.append(expression.substring(offset, matcher.start()));\r
+\r
+                       String name = matcher.group(1);\r
+                       \r
+                       Lookup potential = mdl.getLookup(name);\r
+                       \r
+                       if (potential != null) {\r
+                               System.err.println("found lookup "+name);\r
+                               name = name.replaceAll("\\s+", "");\r
+                       }\r
+                       \r
+                       result.append(name+"(");\r
+                       offset = matcher.end();\r
+               }\r
+               if (offset < expression.length()) {\r
+                       result.append(expression.substring(offset));\r
+               }\r
+               \r
+               return result.toString();\r
+       }\r
+       \r
        public static String replaceSubscripts(String expression, String subscript, String replacement) {\r
                StringBuilder result = new StringBuilder();\r
                int offset = 0;\r
                \r
-               System.err.println("replace subscripts "+subscript+" with "+replacement+" in "+expression);\r
-\r
                Matcher matcher = Pattern.compile(SUBSCRIPT).matcher(expression);\r
                while (matcher.find()) {\r
                        result.append(expression.substring(offset, matcher.start()));\r
index ae22514fe04bc3d1626772a31ada8c173fa1ed8c..b166a32d816a1e723bc7039104a97d4b6b537dec 100644 (file)
@@ -52,8 +52,7 @@ public class Lookup extends Declaration {
                        return null;\r
                }\r
                \r
-               // TODO: capitalize this?\r
-               String name = MdlUtil.normalize(matcher.group(lookupName));\r
+               String name = matcher.group(lookupName).toUpperCase();\r
                double xMin = Double.parseDouble(matcher.group(lookupRangeXMin));\r
                double yMin = Double.parseDouble(matcher.group(lookupRangeYMin));\r
                double xMax = Double.parseDouble(matcher.group(lookupRangeXMax));\r
@@ -97,10 +96,30 @@ public class Lookup extends Declaration {
        }\r
        \r
        public Function getFunction() {\r
-               if (function == null) {\r
-                       function = null;\r
+               if (function != null) {\r
+                       return function;\r
                }\r
                \r
+               StringBuilder body = new StringBuilder();\r
+               \r
+               // one input, one output\r
+               body.append("input Real i;\n");\r
+               body.append("output Real o;\n");\r
+               \r
+               // interpolate over the set of points\r
+               body.append("algorithm\n");\r
+               \r
+               body.append("o := interpolate(i, {");\r
+               for (int i = 0; i < points.length/2; i++) {\r
+                       if (i > 0) {\r
+                               body.append(',');\r
+                       }\r
+                       body.append('{').append(points[2*i]).append(',').append(points[2*i+1]).append('}');\r
+               }\r
+               body.append("});\n");\r
+               \r
+               function = new Function(getName().replaceAll("\\s+", ""), body.toString());\r
+               \r
                return function;\r
        }\r
        \r
index 0fc0d91c61c279075e6dd96dc16d0292dbe61de6..8cae21d9c1af4121c49c565c67445dbd97f5af86 100644 (file)
@@ -65,8 +65,8 @@ public class SketchComment extends SketchElement {
                        return new Comment(getDimensions(), "I/O objects are not supported");\r
                \r
                switch(icon) {\r
-               case CLOUD: return new Cloud(getDimensions());\r
-               case OTHER: return new Comment(getDimensions(), text);\r
+               case CLOUD: return new Cloud(getDimensions(sketch));\r
+               case OTHER: return new Comment(getDimensions(sketch), text);\r
                default: return null;\r
                }\r
        }\r
index 1a27e8739351004d081c6173cbfe6637560fc9d4..2d0c88cedc486f4eb0be7581483c6dcf8e53e803 100644 (file)
@@ -50,7 +50,7 @@ public class SketchValve extends SketchElement {
                \r
                Valve valve = new Valve(Orientation.HORIZONTAL, getTextPosition());\r
                \r
-               return variable.setUpModelVariable(valve, getDimensions(), mdl);\r
+               return variable.setUpModelVariable(valve, getDimensions(sketch), mdl);\r
        }\r
 \r
 }\r
index bed7ca725bd319ba72252f5549f6b21d58e32adb..23bf744e23df5de9704695ce9897a14887f7902c 100644 (file)
@@ -12,6 +12,7 @@ import java.util.regex.Pattern;
 \r
 import org.simantics.sysdyn.modelImport.MdlUtil;\r
 import org.simantics.sysdyn.modelImport.model.expression.EnumerationExpression;\r
+import org.simantics.sysdyn.modelImport.model.expression.NormalExpression;\r
 import org.simantics.sysdyn.modelImport.model.support.Enumeration;\r
 \r
 public class SubscriptVariable extends Variable {\r
@@ -113,9 +114,50 @@ public class SubscriptVariable extends Variable {
                \r
                EnumerationExpression expr = new EnumerationExpression(enumerations);\r
                \r
-               // populate the created expression (this is very complicated)\r
+               // populate the created expression (TODO: comment)\r
                \r
-               System.err.println("populate subscripts for variable "+getName());\r
+               // TODO: is this check correct, also does not work correctly yet\r
+               if (next == null && enumerations.size() == 2) {\r
+                       // option a:\r
+//                     StringBuilder buffer = new StringBuilder();\r
+//                     buffer.append('{');\r
+//                     for (int i = 0; i < values.length; i++) {\r
+//                             if (i > 0) {\r
+//                                     buffer.append(',');\r
+//                             }\r
+//                             buffer.append('{');\r
+//                             for (int j = 0; j < values[i].length; j++) {\r
+//                                     if (j > 0) {\r
+//                                             buffer.append(',');\r
+//                                     }\r
+//                                     buffer.append(values[i][j]);\r
+//                             }\r
+//                             buffer.append('}');\r
+//                     }\r
+//                     buffer.append('}');\r
+//\r
+//                     String[] exprindices = new String[enumerations.size()];\r
+//                     for (int i = 0; i < exprindices.length; i++) {\r
+//                             exprindices[i] = enumerations.get(i).getName();\r
+//                     }\r
+//\r
+//                     expr.addExpression(new NormalExpression(buffer.toString()), exprindices);\r
+//                     return expr;\r
+                       \r
+                       // option b: (probably more sensible)\r
+                       double[][] values = getPossibleValueArray(getExpressionString());\r
+                       if (values != null) {\r
+                               for (int i = 0; i < values.length; i++) {\r
+                                       for (int j = 0; j < values[i].length; j++) {\r
+                                               expr.addExpression(\r
+                                                               new NormalExpression(Double.toString(values[i][j])),\r
+                                                               enumerations.get(0).getValues().get(i),\r
+                                                               enumerations.get(1).getValues().get(j));\r
+                                       }\r
+                               }\r
+                               return expr;\r
+                       }\r
+               }\r
                \r
                var = this;\r
                while (var != null) {\r
@@ -144,7 +186,12 @@ public class SubscriptVariable extends Variable {
                        }\r
                        \r
                        for (WorkExpression we : workqueue) {\r
-                               expr.addExpression(parseExpression(MdlUtil.expandIterations(we.expression, mdl)), we.indices);\r
+                               // TODO: is this check correct\r
+                               String expression = MdlUtil.finalize(we.expression, mdl);\r
+                               if (next == null) {\r
+                                       expression = removeComparisons(expression, indices, we.indices);\r
+                               }\r
+                               expr.addExpression(parseExpression(expression), we.indices);\r
                        }\r
                        \r
                        var = var.getNext();\r
@@ -162,5 +209,63 @@ public class SubscriptVariable extends Variable {
                        this.expression = expression;\r
                }\r
        }\r
+       \r
+       private static double[][] getPossibleValueArray(String expression) {\r
+               // (number(,number)*;)*\r
+               Matcher matcher = Pattern.compile(\r
+                       "("+MdlUtil.DBL+"(,"+MdlUtil.DBL+")*;)*"\r
+                               ).matcher(expression);\r
+               \r
+               if (!matcher.matches()) {\r
+                       return null;\r
+               }\r
+               \r
+               String[] rows = expression.split(";");\r
+               double[][] result = new double[rows.length][];\r
+               for (int i = 0; i < rows.length; i++) {\r
+                       String[] columns = rows[i].split(",");\r
+                       result[i] = new double[columns.length];\r
+                       for (int j = 0; j < columns.length; j++) {\r
+                               result[i][j] = Double.parseDouble(columns[j]);\r
+                       }       \r
+               }\r
+               \r
+               return result;\r
+       }\r
+       \r
+       private static String removeComparisons(String expression, String[] subscripts, String[] values) {\r
+               \r
+               if (!expression.contains("=")) {\r
+                       return expression;\r
+               }\r
+                               \r
+               for (int i = 0; i < subscripts.length; i++) {\r
+                       for (int j = 0; j < subscripts.length; j++) {\r
+                               StringBuilder result = new StringBuilder();\r
+                               int offset = 0;\r
+                               \r
+                               Matcher matcher = Pattern.compile(subscripts[i]+"\\s*=\\s*"+subscripts[j]).matcher(expression);\r
+                               while (matcher.find()) {\r
+                                       result.append(expression.substring(offset, matcher.start()));\r
+                                       \r
+                                       if (values[i].equals(values[j])) {\r
+                                               result.append("true");\r
+                                       }\r
+                                       else {\r
+                                               result.append("false");\r
+                                       }\r
+                                       \r
+                                       offset = matcher.end();\r
+                               }\r
+                               if (offset < expression.length()) {\r
+                                       result.append(expression.substring(offset));\r
+                               }\r
+                               \r
+                               expression = result.toString();\r
+                       }\r
+               }\r
+               \r
+               return expression;\r
+       }\r
 \r
 }\r
index f93e707526a3fe50de1e9e0a94836e8dba8b527b..7dceeaef9dae2457889103cd7ff6b95f6ace4f3a 100644 (file)
@@ -73,7 +73,7 @@ public class Variable extends Declaration {
        }\r
        \r
        public Expression getExpression(MdlModel mdl) {\r
-               return parseExpression(MdlUtil.expandIterations(expression, mdl));\r
+               return parseExpression(MdlUtil.finalize(expression, mdl));\r
        }\r
        \r
        protected static Expression parseExpression(String expression) {\r
@@ -104,6 +104,20 @@ public class Variable extends Declaration {
                        }\r
                        return new DelayExpression(parameters[0], parameters[1], parameters[2], Integer.parseInt(parameters[3]));\r
                }\r
+               else if (function.startsWith("SMOOTHI")) {\r
+                       if (parameters.length != 3) {\r
+                               System.err.println("malformed smoothi expression: "+expression);\r
+                       }\r
+                       // what is the correct degree for smooth?\r
+                       return new DelayExpression(parameters[0], parameters[1], parameters[2], 1);\r
+               }\r
+               else if (function.startsWith("SMOOTH")) {\r
+                       if (parameters.length != 2) {\r
+                               System.err.println("malformed smooth expression: "+expression);\r
+                       }\r
+                       // what is the correct degree and initial value for smooth?\r
+                       return new DelayExpression(parameters[0], parameters[1], parameters[0], 1);\r
+               }\r
                else if (function.startsWith("GAME")) {\r
                        // a game expression, currently treated as a normal expression\r
                        if (parameters.length != 1) {\r
index 38bde81be22f86dc4a9b8d587552a5f10d9c2460..0b56e6e6e890548b8ce7ce7ab5001bc8119bcfa9 100644 (file)
@@ -165,7 +165,7 @@ public class Model implements IWriteableObject {
                }\r
                \r
                for (Function f : getFunctions()) {\r
-                       f.write(graph, configuration, context);\r
+                       f.write(graph, model, context);\r
                }\r
                \r
                for (Symbol e : symbols) {\r
index f2f84ebab2c002fffc112b7ff98e77c8622d7be1..8f68915d9239b7b437766c9eb6d1303dec2095d5 100644 (file)
@@ -33,8 +33,9 @@ public class LookupExpression extends Expression {
                StringBuilder lookup = new StringBuilder();\r
                lookup.append('{');\r
                for (int i = 0; i < points.length / 2; i++) {\r
-                       if (i > 0)\r
+                       if (i > 0) {\r
                                lookup.append(',');\r
+                       }\r
                        lookup.append('{').append(points[2*i]).append(',').append(points[2*i+1]).append('}');\r
                }\r
                lookup.append('}');\r
index 7f086e92dd46ea3749bcb99bc9a49b613e19ea82..faa5f5a6445093eeb75558c8c884b28de179c02c 100644 (file)
@@ -2,34 +2,66 @@ package org.simantics.sysdyn.modelImport.model.support;
 \r
 import java.util.List;\r
 \r
+import org.simantics.databoard.Bindings;\r
 import org.simantics.db.Resource;\r
 import org.simantics.db.WriteGraph;\r
 import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.layer0.utils.direct.GraphUtils;\r
+import org.simantics.sysdyn.SysdynResource;\r
 import org.simantics.sysdyn.modelImport.model.IWriteableObject;\r
 import org.simantics.sysdyn.modelImport.model.WriteContext;\r
 \r
 public class Function implements IWriteableObject {\r
 \r
        private String name;\r
+       private String body;\r
+       private String description;\r
        \r
-       public Function(String name, List<String> inputs, List<String> outputs, String code) {\r
+       private Resource function;\r
+       \r
+       public Function(String name, String body) {\r
+               this(name, body, null);\r
+       }\r
+       \r
+       public Function(String name, String body, String description) {\r
                this.name = name;\r
+               this.body = body;\r
+               this.description = description;\r
        }\r
        \r
        public String getName() {\r
                return name;\r
        }\r
        \r
+       public String getBody() {\r
+               return body;\r
+       }\r
+       \r
        @Override\r
        public Resource write(WriteGraph graph, Resource parent, WriteContext context) \r
                        throws DatabaseException {\r
                System.err.println("write function");\r
-               return null;\r
+               \r
+               Layer0 l0 = Layer0.getInstance(graph);\r
+               SysdynResource sr = SysdynResource.getInstance(graph);\r
+               \r
+               function = GraphUtils.create2(graph, sr.SysdynModelicaFunction, \r
+                               l0.HasName, name,\r
+                               l0.PartOf, parent);\r
+               \r
+               graph.claimLiteral(function, sr.SysdynModelicaFunction_modelicaFunctionCode, body, Bindings.STRING);\r
+               \r
+               if (description != null) {\r
+                       graph.claimLiteral(function, l0.HasDescription, body, Bindings.STRING);\r
+               }\r
+               \r
+               return function;\r
        }\r
 \r
        @Override\r
        public Resource getResource() {\r
-               return null;\r
+               return function;\r
        }\r
        \r
 }\r
index fc9415c7cc496a34973603fc321c8d91dfbe59f5..1b191676cc81a23fdace06807ff7db8bf60f0300 100644 (file)
@@ -31,6 +31,8 @@ import org.simantics.sysdyn.representation.ModuleType;
 import org.simantics.sysdyn.representation.Sheet;\r
 import org.simantics.sysdyn.representation.Stock;\r
 import org.simantics.sysdyn.representation.Variable;\r
+import org.simantics.sysdyn.representation.expressions.DelayExpression;\r
+import org.simantics.sysdyn.representation.expressions.IExpression;\r
 \r
 /**\r
  * ModelicaWriter writes Sysdyn model representations (objmap) into Modelica code.\r
@@ -41,387 +43,462 @@ import org.simantics.sysdyn.representation.Variable;
  */\r
 public class ModelicaWriter {\r
 \r
-    /**\r
-     * Write a collection of configurations into a single Modelica code\r
-     * @param isGame \r
-     * \r
-     * @param Configurations Configurations, one main configuration and possible modules\r
-     * @return Complete Modelica code of a model\r
-     */\r
-    public static String write(Collection<Configuration> _configurations, boolean isGame, String omVersion) {\r
-       \r
-       ArrayList<Configuration> configurations = new ArrayList<Configuration>(_configurations);\r
-       Collections.sort(configurations, new Comparator<Configuration>() {\r
-\r
-               boolean uses(Configuration o1, Configuration o2) {\r
-                       ModuleType type = o2.getModuleType();\r
-                       if(type == null) return false;\r
-                       for(IElement e : o1.getElements()) {\r
-                               if(e instanceof Module) {\r
-                                       Module m = (Module)e;\r
-                                       if(m.getType().equals(type)) {\r
-                                               return true;\r
-                                       }\r
-                               }\r
-                       }\r
-                       return false;\r
-               }\r
-               \r
+       /**\r
+        * Write a collection of configurations into a single Modelica code\r
+        * @param isGame \r
+        \r
+        * @param Configurations Configurations, one main configuration and possible modules\r
+        * @return Complete Modelica code of a model\r
+        */\r
+       public static String write(Collection<Configuration> _configurations, boolean isGame, String omVersion) {\r
+\r
+               ArrayList<Configuration> configurations = new ArrayList<Configuration>(_configurations);\r
+               Collections.sort(configurations, new Comparator<Configuration>() {\r
+\r
+                       boolean uses(Configuration o1, Configuration o2) {\r
+                               ModuleType type = o2.getModuleType();\r
+                               if(type == null) return false;\r
+                               for(IElement e : o1.getElements()) {\r
+                                       if(e instanceof Module) {\r
+                                               Module m = (Module)e;\r
+                                               if(m.getType().equals(type)) {\r
+                                                       return true;\r
+                                               }\r
+                                       }\r
+                               }\r
+                               return false;\r
+                       }\r
+\r
                        @Override\r
                        public int compare(Configuration o1, Configuration o2) {\r
-                       if(uses(o1, o2)) return 1;\r
-                       else if(uses(o2, o1)) return -1;\r
-                       else return 0;\r
+                               if(uses(o1, o2)) return 1;\r
+                               else if(uses(o2, o1)) return -1;\r
+                               else return 0;\r
                        }\r
-                       \r
+\r
                });\r
-       \r
-        Configuration modelConf = null;\r
-        for(Configuration conf : configurations) {\r
-            if(conf.getModel() != null) {\r
-                modelConf = conf;\r
-            }\r
-        }\r
-        StringBuilder b = new StringBuilder();\r
-        \r
-        int spreadsheetlocation = b.length();\r
-\r
-        String modelName = modelConf.getLabel().replace(" ", "");\r
-        b.append("model " + modelName + "\n");\r
-\r
-        // Super class for enumerations\r
-        b.append("partial class Enumeration_class\n");\r
-        b.append("    parameter Integer size;\n");\r
-        b.append("    parameter Integer elements[:];\n");\r
-        b.append("end Enumeration_class;\n\n");\r
-        \r
-        \r
-        HashSet<String> sheetNames = new HashSet<String>();\r
-        for(Sheet sheet : getSpreadSheets(configurations))\r
-            sheetNames.add(sheet.getModelicaName());\r
-        \r
-        // Write all module configurations to the declarations part (first)\r
-        for(Configuration conf : configurations) {\r
-            conf.setIsGameConfiguration(isGame);\r
-            if(!conf.equals(modelConf))\r
-                writeConfiguration(conf, sheetNames, b);\r
-        }\r
-        \r
-        // Write model configuration last, so that equations-part does not contain module definitions\r
-        modelConf.setIsGameConfiguration(isGame);\r
-        writeConfiguration(modelConf, sheetNames, b);\r
-        \r
-        b.append("end " + modelName + ";\n\n");\r
-        \r
-        // Insert spreadsheets\r
-        if(omVersion != null && omVersion.startsWith("1.9")) {\r
-            b.insert(spreadsheetlocation, getGlobalSpreadSheets(configurations));\r
-        } else {\r
-            b.append(getGlobalSpreadSheets(configurations));\r
-        }\r
-\r
-        \r
-        return b.toString();\r
-    }\r
-    \r
-    /**\r
-     * Get all spreadsheets that are found in the model\r
-     * @param configurations\r
-     * @return\r
-     */\r
-    private static List<Sheet> getSpreadSheets(Collection<Configuration> configurations) {\r
-        for(Configuration conf : configurations) {\r
-            if(conf.getModel() != null) {\r
-                for(IElement e : conf.getElements()) {\r
-                    if(e instanceof Book) {\r
-                        return ((Book)e).getSheets();\r
-                    }\r
-                }\r
-            }\r
-        }\r
-        return Collections.emptyList();\r
-    }\r
-    \r
-    /**\r
-     * \r
-     */\r
-    private static String getGlobalSpreadSheets(Collection<Configuration> configurations) {\r
-       StringBuilder sheets = new StringBuilder();\r
-       for(Configuration conf : configurations) {\r
-               if(conf.getModel() != null) {\r
-                       for(IElement e : conf.getElements()) {\r
-                               if(e instanceof Book) {\r
-                                       return ((Book)e).getBook();\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       \r
-       return sheets.toString();\r
-    }\r
-\r
-    /**\r
-     * Write a single configuration to a given string builder\r
-     * \r
-     * @param configuration Model or module configuration\r
-     * @param b String builder\r
-     */\r
-    private static void writeConfiguration(Configuration configuration, HashSet<String> sheetNames, StringBuilder b) {\r
-        boolean defTime = true;\r
-        String app;\r
-        \r
-        // Lists for storing different configuration elements\r
-        ArrayList<IndependentVariable> variables = new ArrayList<IndependentVariable>();\r
-        ArrayList<Input> inputs = new ArrayList<Input>();\r
-        ArrayList<Module> modules = new ArrayList<Module>();\r
-        ArrayList<Stock> stocks = new ArrayList<Stock>();\r
-        ArrayList<Enumeration> enumerations = new ArrayList<Enumeration>();\r
-        ArrayList<Dependency> inputDependencies = new ArrayList<Dependency>();\r
-        ArrayList<Dependency> outputDependencies = new ArrayList<Dependency>();\r
-        HashMap<String, ArrayList<Input>> moduleInputs = new HashMap<String, ArrayList<Input>>();\r
-\r
-        // Initialize lists\r
-        for(IElement element : configuration.getElements()) {\r
-            if(element instanceof IndependentVariable) {\r
-                // Normal variable\r
-                variables.add((IndependentVariable)element);\r
-                if(element instanceof Stock)\r
-                    // Stock\r
-                    stocks.add((Stock)element);\r
-            } else if (element instanceof Module) {\r
-                // Module\r
-                Module m = (Module)element; \r
-                modules.add(m);\r
-                moduleInputs.put(m.getName(), new ArrayList<Input>());\r
-                for(IElement e : m.getType().getConfiguration().getElements())\r
-                    // Inputs inside the module\r
-                    if(e instanceof Input && !((Input)e).isHeadOfDependency()) {\r
-                        moduleInputs.get(m.getName()).add((Input)e);\r
-                    }\r
-            } else if (element instanceof Input) {\r
-                // Input variables\r
-                inputs.add((Input)element);\r
-            } else if (element instanceof Enumeration) {\r
-                // Enumerations\r
-                enumerations.add((Enumeration)element);\r
-            } else if (element instanceof Dependency) {\r
-                Dependency dependency = (Dependency)element;\r
-                if(dependency.getHead() instanceof Module) {\r
-                    // References given to child modules\r
-                    outputDependencies.add(dependency);\r
-                } else if(dependency.getTail() instanceof Module){\r
-                    // References from child modules\r
-                    inputDependencies.add(dependency);\r
-                }\r
-            }\r
-        }\r
-        \r
-        // Setup input references. (Input, String reference to another variable)\r
-        HashMap<Input, String> inputReferences = new HashMap<Input, String>();\r
-        setupInputReferences(inputReferences, inputDependencies);\r
-        \r
-\r
-        // If the configuration is model configuration, use model name. Otherwise, use configuration name.\r
-        ModuleType mt = configuration.getModuleType();\r
-        \r
-        // className == null, if this is a model configuration. model configuration start and end are written in ModelicaWriter.write\r
-        String className = mt != null ? (mt.getName().replace(" ", "")) : null;\r
-        \r
-        if(className != null)\r
-            b.append("\nclass ").append(className);\r
-        \r
-        // Add spreadsheets to all modules and model. Model is "inner" and modules "outer"\r
-        String globalStatus = mt != null ? "outer" : "inner";\r
-        for(String sheetName : sheetNames)\r
-               b.append("\n    " + globalStatus + " " + sheetName + "_class" + " "+ sheetName + ";");\r
-        \r
-        b.append("\n");\r
-\r
-\r
-        if(!enumerations.isEmpty()) {\r
-            b.append("// Enumeration definitions\n");\r
-            for(Enumeration e : enumerations) {\r
-                b.append(e.getDeclaration());\r
-            }\r
-        }\r
-\r
-        b.append("// Variable definitions\n");\r
-        for(IndependentVariable variable : variables) {\r
-            app = variable.getDeclaration();\r
-            if (app != null) b.append(app);\r
-        }\r
-        \r
-        if(defTime) {\r
-            // Time variable for FMU (game) simulations\r
-            if(configuration.isGameConfiguration()) {\r
-                if(configuration.getModel() != null)\r
-                    // Parameter for model root. Values changed in FMU simulator\r
-                    b.append("    parameter Real time = 0;\n");\r
-                else\r
-                    // Continuous variable for module instances\r
-                    b.append("    Real time;\n");\r
-\r
-            }\r
-        }\r
-\r
-        if(!modules.isEmpty()) {\r
-            b.append("// Module definitions\n");\r
-            for(Module m : modules) {\r
-                b.append(m.getDeclaration());\r
-            }\r
-        }\r
-\r
-\r
-        // Input definitions\r
-        inputDefinitions(b, configuration, inputs, inputReferences);\r
-\r
-        boolean initialEquations = false;\r
-        for(Stock stock : stocks) {\r
-            app = stock.getInitialEquation();\r
-            if (app != null) {\r
-                if(initialEquations == false) {\r
-                    initialEquations = true;\r
-                    b.append("// Initial Equations\n");\r
-                    b.append("initial equation\n");\r
-                }\r
-                b.append(app);\r
-            }\r
-        }\r
-\r
-        boolean equation = false;\r
-        b.append("// Equations\n");\r
-        for(IndependentVariable variable : variables) {\r
-            app = variable.getEquation();\r
-            if (app != null) {\r
-                if(!equation) {\r
-                    b.append("equation\n");\r
-                    equation = true;\r
-                }\r
-                \r
-                b.append(app);\r
-            }\r
-        }\r
-        \r
-        // If "equation" has not been added but there are still equations to be defined, add "equation"\r
-        if(!equation && (!inputReferences.isEmpty() || !outputDependencies.isEmpty() ||\r
-                !moduleInputs.isEmpty() || !modules.isEmpty()))\r
-            b.append("equation\n");\r
-\r
-        // Continous input references\r
-        continuousInputReferences(b, inputReferences);\r
-        \r
-        b.append("// Outputs\n");\r
-        for(Dependency dependency : outputDependencies) {\r
-            Variable variable = (Variable)dependency.getTail();\r
-            Module module = (Module)dependency.getHead();\r
-            Input reference = (Input)dependency.refersTo();\r
-            if(reference != null && reference.getName() != null && (reference.getVariability() == null || reference.getVariability().isEmpty())) {\r
-                b.append("    " + module.getName() + "." + reference.getModelicaName() + " = " + variable.getModelicaName() + ";\n");\r
-                moduleInputs.get(module.getName()).remove(reference);\r
-            }\r
-        }\r
-\r
-        b.append("// Default values for inputs in modules\n");\r
-        for(String moduleLabel : moduleInputs.keySet()) {\r
-            for(Input input : moduleInputs.get(moduleLabel)) {\r
-                if(input.getVariability() == null || input.getVariability().isEmpty())\r
-                    b.append("    " + moduleLabel + "." + input.getModelicaName() + " = " + input.getDefaultInputValue(moduleLabel) + ";\n");\r
-            }\r
-        }\r
-        \r
-        if(defTime) {\r
-            if(configuration.isGameConfiguration() && !modules.isEmpty()) {\r
-                b.append("// Time values for module\n");\r
-                for(Module m : modules) {\r
-                    b.append("    " + m.getName() + ".time = time;\n");\r
-                }\r
-            }\r
-        }\r
-\r
-        if(className != null)\r
-            b.append("end ").append(className).append(";\n\n");\r
-\r
-    }\r
-    \r
+\r
+               Configuration modelConf = null;\r
+               for(Configuration conf : configurations) {\r
+                       if(conf.getModel() != null) {\r
+                               modelConf = conf;\r
+                       }\r
+               }\r
+               StringBuilder b = new StringBuilder();\r
+\r
+               int spreadsheetlocation = b.length();\r
+\r
+               String modelName = modelConf.getLabel().replace(" ", "");\r
+               b.append("model " + modelName + "\n");\r
+\r
+               // Super class for enumerations\r
+               b.append("partial class Enumeration_class\n");\r
+               b.append("    parameter Integer size;\n");\r
+               b.append("    parameter Integer elements[:];\n");\r
+               b.append("end Enumeration_class;\n\n");\r
+\r
+               // find out which delays are used in the model and create the\r
+               // necessary classes\r
+               HashSet<Integer> delays = new HashSet<Integer>();\r
+               for (Configuration configuration : configurations) {\r
+                       for (IElement element : configuration.getElements()) {\r
+                               if (element instanceof IndependentVariable) {\r
+                                       for (IExpression expression : ((IndependentVariable)element).getExpressions()) {\r
+                                               if (expression instanceof DelayExpression) {\r
+                                                       delays.add(((DelayExpression)expression).getOrder());\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               for (Integer i : delays) {\r
+                       b.append(getDelayClass(i));\r
+                       b.append("\n");\r
+               }\r
+\r
+               HashSet<String> sheetNames = new HashSet<String>();\r
+               for(Sheet sheet : getSpreadSheets(configurations))\r
+                       sheetNames.add(sheet.getModelicaName());\r
+\r
+               // Write all module configurations to the declarations part (first)\r
+               for(Configuration conf : configurations) {\r
+                       conf.setIsGameConfiguration(isGame);\r
+                       if(!conf.equals(modelConf))\r
+                               writeConfiguration(conf, sheetNames, b);\r
+               }\r
+\r
+               // Write model configuration last, so that equations-part does not contain module definitions\r
+               modelConf.setIsGameConfiguration(isGame);\r
+               writeConfiguration(modelConf, sheetNames, b);\r
+\r
+               b.append("end " + modelName + ";\n\n");\r
+\r
+               // Insert spreadsheets\r
+               if(omVersion != null && omVersion.startsWith("1.9")) {\r
+                       b.insert(spreadsheetlocation, getGlobalSpreadSheets(configurations));\r
+               } else {\r
+                       b.append(getGlobalSpreadSheets(configurations));\r
+               }\r
+\r
+               return b.toString();\r
+       }\r
+\r
+       /**\r
+        * Get all spreadsheets that are found in the model\r
+        * @param configurations\r
+        * @return\r
+        */\r
+       private static List<Sheet> getSpreadSheets(Collection<Configuration> configurations) {\r
+               for(Configuration conf : configurations) {\r
+                       if(conf.getModel() != null) {\r
+                               for(IElement e : conf.getElements()) {\r
+                                       if(e instanceof Book) {\r
+                                               return ((Book)e).getSheets();\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               return Collections.emptyList();\r
+       }\r
+\r
+       /**\r
+        * \r
+        */\r
+       private static String getGlobalSpreadSheets(Collection<Configuration> configurations) {\r
+               StringBuilder sheets = new StringBuilder();\r
+               for(Configuration conf : configurations) {\r
+                       if(conf.getModel() != null) {\r
+                               for(IElement e : conf.getElements()) {\r
+                                       if(e instanceof Book) {\r
+                                               return ((Book)e).getBook();\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               return sheets.toString();\r
+       }\r
+\r
        /**\r
-     * Define continuous input references\r
-     * @param b String builder\r
-     * @param inputReferences Input references\r
-     */\r
-    private static void continuousInputReferences(StringBuilder b, HashMap<Input, String> inputReferences) {\r
-        b.append("// Inputs\n");\r
-        for(Input i : inputReferences.keySet()) {\r
-            if(i.getVariability() == null || i.getVariability().isEmpty()) {\r
-                // Define only continuous variables here\r
-                b.append("    " + i.getModelicaName() + " = " + inputReferences.get(i));\r
-            }\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Setup input references for all inputs that are defined in child modules\r
-     * \r
-     * @param inputReferences Map containing the references\r
-     * @param inputDependencies List of input dependencies\r
-     */\r
-    private static void setupInputReferences(HashMap<Input, String> inputReferences, ArrayList<Dependency> inputDependencies) {\r
-        for(Dependency dependency : inputDependencies) {\r
-            Input input = (Input)dependency.getHead();\r
-            Module module = (Module)dependency.getTail();\r
-            Variable reference = (Variable)dependency.refersTo();\r
-            String expression;\r
-            // If reference exists, use reference name. Otherwise, use default value.\r
-            if(reference != null && reference.getName() != null)\r
-                expression = module.getName() + "." + reference.getModelicaName() + ";\n";\r
-\r
-            else\r
-                expression = input.getDefaultInputValue() + ";\n";\r
-            \r
-            inputReferences.put(input, expression);\r
-        }\r
-    }\r
-\r
-    /**\r
-     *  Build input definitions\r
-     * \r
-     * @param b String builder\r
-     * @param configuration Module configuration\r
-     * @param inputs All inputs of this module\r
-     * @param inputReferences \r
-     */\r
-    private static void inputDefinitions(StringBuilder b, Configuration configuration, ArrayList<Input> inputs, HashMap<Input, String> inputReferences) {\r
-        if(inputs.isEmpty())\r
-            return;\r
-        \r
-        b.append("// Input definitions\n");\r
-        for(Input i : inputs) {\r
-            if(i.getVariability() != null && !i.getVariability().isEmpty()) {\r
-                // Input is NOT continuous\r
-                if(inputReferences.containsKey(i)) {\r
-                    // Input is defined in a child module\r
-                    String declaration = i.getDeclaration();\r
-                    declaration = declaration.substring(0, declaration.length() - 2); // remove ";\n" from the end\r
-                    b.append(declaration + " = " + inputReferences.get(i));\r
-                } else {\r
-                    // Input is not defined in a child module, use default value\r
-                    b.append(i.getDeclarationWithValue());\r
-                }\r
-            } else if(configuration.getModel() != null && !i.isHeadOfDependency()) {\r
-                /*\r
-                 *  Input is in the top of the hierarchy, \r
-                 *  and it does not get value from anywhere else.\r
-                 *  => Declare it wit its default value \r
-                 */\r
-                b.append(i.getDeclarationWithValue());\r
-            } else {\r
-                // Continuous => Parent module takes care of declaring a value for the input\r
-                b.append(i.getDeclaration());\r
-            }\r
-        }\r
-    }\r
-\r
-    public String escape(String name) {\r
-        return name.replace(' ', '_');\r
-    }\r
+        * Write a single configuration to a given string builder\r
+        * \r
+        * @param configuration Model or module configuration\r
+        * @param b String builder\r
+        */\r
+       private static void writeConfiguration(Configuration configuration, HashSet<String> sheetNames, StringBuilder b) {\r
+               boolean defTime = true;\r
+               String app;\r
+\r
+               // Lists for storing different configuration elements\r
+               ArrayList<IndependentVariable> variables = new ArrayList<IndependentVariable>();\r
+               ArrayList<Input> inputs = new ArrayList<Input>();\r
+               ArrayList<Module> modules = new ArrayList<Module>();\r
+               ArrayList<Stock> stocks = new ArrayList<Stock>();\r
+               ArrayList<Enumeration> enumerations = new ArrayList<Enumeration>();\r
+               ArrayList<Dependency> inputDependencies = new ArrayList<Dependency>();\r
+               ArrayList<Dependency> outputDependencies = new ArrayList<Dependency>();\r
+               HashMap<String, ArrayList<Input>> moduleInputs = new HashMap<String, ArrayList<Input>>();\r
+\r
+               // Initialize lists\r
+               for(IElement element : configuration.getElements()) {\r
+                       if(element instanceof IndependentVariable) {\r
+                               // Normal variable\r
+                               variables.add((IndependentVariable)element);\r
+                               if(element instanceof Stock)\r
+                                       // Stock\r
+                                       stocks.add((Stock)element);\r
+                       } else if (element instanceof Module) {\r
+                               // Module\r
+                               Module m = (Module)element; \r
+                               modules.add(m);\r
+                               moduleInputs.put(m.getName(), new ArrayList<Input>());\r
+                               for(IElement e : m.getType().getConfiguration().getElements())\r
+                                       // Inputs inside the module\r
+                                       if(e instanceof Input && !((Input)e).isHeadOfDependency()) {\r
+                                               moduleInputs.get(m.getName()).add((Input)e);\r
+                                       }\r
+                       } else if (element instanceof Input) {\r
+                               // Input variables\r
+                               inputs.add((Input)element);\r
+                       } else if (element instanceof Enumeration) {\r
+                               // Enumerations\r
+                               enumerations.add((Enumeration)element);\r
+                       } else if (element instanceof Dependency) {\r
+                               Dependency dependency = (Dependency)element;\r
+                               if(dependency.getHead() instanceof Module) {\r
+                                       // References given to child modules\r
+                                       outputDependencies.add(dependency);\r
+                               } else if(dependency.getTail() instanceof Module){\r
+                                       // References from child modules\r
+                                       inputDependencies.add(dependency);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               // Setup input references. (Input, String reference to another variable)\r
+               HashMap<Input, String> inputReferences = new HashMap<Input, String>();\r
+               setupInputReferences(inputReferences, inputDependencies);\r
+\r
+\r
+               // If the configuration is model configuration, use model name. Otherwise, use configuration name.\r
+               ModuleType mt = configuration.getModuleType();\r
+\r
+               // className == null, if this is a model configuration. model configuration start and end are written in ModelicaWriter.write\r
+               String className = mt != null ? (mt.getName().replace(" ", "")) : null;\r
+\r
+               if(className != null)\r
+                       b.append("class "+className+"\n").append(className);\r
+\r
+               // Add spreadsheets to all modules and model. Model is "inner" and modules "outer"\r
+               String globalStatus = mt != null ? "outer" : "inner";\r
+               for(String sheetName : sheetNames)\r
+                       b.append("    " + globalStatus + " " + sheetName + "_class" + " "+ sheetName + ";\n");\r
+\r
+               if(!enumerations.isEmpty()) {\r
+                       b.append("// Enumeration definitions\n");\r
+                       for(Enumeration e : enumerations) {\r
+                               b.append(e.getDeclaration());\r
+                       }\r
+               }\r
+\r
+               b.append("// Variable definitions\n");\r
+               for(IndependentVariable variable : variables) {\r
+                       app = variable.getDeclaration();\r
+                       if (app != null) b.append(app);\r
+               }\r
+\r
+               if(defTime) {\r
+                       // Time variable for FMU (game) simulations\r
+                       if(configuration.isGameConfiguration()) {\r
+                               if(configuration.getModel() != null)\r
+                                       // Parameter for model root. Values changed in FMU simulator\r
+                                       b.append("    parameter Real time = 0;\n");\r
+                               else\r
+                                       // Continuous variable for module instances\r
+                                       b.append("    Real time;\n");\r
+\r
+                       }\r
+               }\r
+\r
+               if(!modules.isEmpty()) {\r
+                       b.append("// Module definitions\n");\r
+                       for(Module m : modules) {\r
+                               b.append(m.getDeclaration());\r
+                       }\r
+               }\r
+\r
+\r
+               // Input definitions\r
+               inputDefinitions(b, configuration, inputs, inputReferences);\r
+\r
+               boolean initialEquations = false;\r
+               for(Stock stock : stocks) {\r
+                       app = stock.getInitialEquation();\r
+                       if (app != null) {\r
+                               if(initialEquations == false) {\r
+                                       initialEquations = true;\r
+                                       b.append("// Initial Equations\n");\r
+                                       b.append("initial equation\n");\r
+                               }\r
+                               b.append(app);\r
+                       }\r
+               }\r
+\r
+               boolean equation = false;\r
+               b.append("// Equations\n");\r
+               for(IndependentVariable variable : variables) {\r
+                       app = variable.getEquation();\r
+                       if (app != null) {\r
+                               if(!equation) {\r
+                                       b.append("equation\n");\r
+                                       equation = true;\r
+                               }\r
+\r
+                               b.append(app);\r
+                       }\r
+               }\r
+\r
+               // If "equation" has not been added but there are still equations to be defined, add "equation"\r
+               if(!equation && (!inputReferences.isEmpty() || !outputDependencies.isEmpty() ||\r
+                               !moduleInputs.isEmpty() || !modules.isEmpty()))\r
+                       b.append("equation\n");\r
+\r
+               // Continuous input references\r
+               continuousInputReferences(b, inputReferences);\r
+\r
+               b.append("// Outputs\n");\r
+               for(Dependency dependency : outputDependencies) {\r
+                       Variable variable = (Variable)dependency.getTail();\r
+                       Module module = (Module)dependency.getHead();\r
+                       Input reference = (Input)dependency.refersTo();\r
+                       if(reference != null && reference.getName() != null && (reference.getVariability() == null || reference.getVariability().isEmpty())) {\r
+                               b.append("    " + module.getName() + "." + reference.getModelicaName() + " = " + variable.getModelicaName() + ";\n");\r
+                               moduleInputs.get(module.getName()).remove(reference);\r
+                       }\r
+               }\r
+\r
+               b.append("// Default values for inputs in modules\n");\r
+               for(String moduleLabel : moduleInputs.keySet()) {\r
+                       for(Input input : moduleInputs.get(moduleLabel)) {\r
+                               if(input.getVariability() == null || input.getVariability().isEmpty())\r
+                                       b.append("    " + moduleLabel + "." + input.getModelicaName() + " = " + input.getDefaultInputValue(moduleLabel) + ";\n");\r
+                       }\r
+               }\r
+\r
+               if(defTime) {\r
+                       if(configuration.isGameConfiguration() && !modules.isEmpty()) {\r
+                               b.append("// Time values for module\n");\r
+                               for(Module m : modules) {\r
+                                       b.append("    " + m.getName() + ".time = time;\n");\r
+                               }\r
+                       }\r
+               }\r
+\r
+               if(className != null)\r
+                       b.append("end ").append(className).append(";\n\n");\r
+\r
+       }\r
+\r
+       /**\r
+        * Define continuous input references\r
+        * @param b String builder\r
+        * @param inputReferences Input references\r
+        */\r
+       private static void continuousInputReferences(StringBuilder b, HashMap<Input, String> inputReferences) {\r
+               b.append("// Inputs\n");\r
+               for(Input i : inputReferences.keySet()) {\r
+                       if(i.getVariability() == null || i.getVariability().isEmpty()) {\r
+                               // Define only continuous variables here\r
+                               b.append("    " + i.getModelicaName() + " = " + inputReferences.get(i));\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Setup input references for all inputs that are defined in child modules\r
+        * \r
+        * @param inputReferences Map containing the references\r
+        * @param inputDependencies List of input dependencies\r
+        */\r
+       private static void setupInputReferences(HashMap<Input, String> inputReferences, ArrayList<Dependency> inputDependencies) {\r
+               for(Dependency dependency : inputDependencies) {\r
+                       Input input = (Input)dependency.getHead();\r
+                       Module module = (Module)dependency.getTail();\r
+                       Variable reference = (Variable)dependency.refersTo();\r
+                       String expression;\r
+                       // If reference exists, use reference name. Otherwise, use default value.\r
+                       if(reference != null && reference.getName() != null)\r
+                               expression = module.getName() + "." + reference.getModelicaName() + ";\n";\r
+\r
+                       else\r
+                               expression = input.getDefaultInputValue() + ";\n";\r
+\r
+                       inputReferences.put(input, expression);\r
+               }\r
+       }\r
+\r
+       /**\r
+        *  Build input definitions\r
+        * \r
+        * @param b String builder\r
+        * @param configuration Module configuration\r
+        * @param inputs All inputs of this module\r
+        * @param inputReferences \r
+        */\r
+       private static void inputDefinitions(StringBuilder b, Configuration configuration, ArrayList<Input> inputs, HashMap<Input, String> inputReferences) {\r
+               if(inputs.isEmpty())\r
+                       return;\r
+\r
+               b.append("// Input definitions\n");\r
+               for(Input i : inputs) {\r
+                       if(i.getVariability() != null && !i.getVariability().isEmpty()) {\r
+                               // Input is NOT continuous\r
+                               if(inputReferences.containsKey(i)) {\r
+                                       // Input is defined in a child module\r
+                                       String declaration = i.getDeclaration();\r
+                                       declaration = declaration.substring(0, declaration.length() - 2); // remove ";\n" from the end\r
+                                       b.append(declaration + " = " + inputReferences.get(i));\r
+                               } else {\r
+                                       // Input is not defined in a child module, use default value\r
+                                       b.append(i.getDeclarationWithValue());\r
+                               }\r
+                       } else if(configuration.getModel() != null && !i.isHeadOfDependency()) {\r
+                               /*\r
+                                *  Input is in the top of the hierarchy, \r
+                                *  and it does not get value from anywhere else.\r
+                                *  => Declare it wit its default value \r
+                                */\r
+                               b.append(i.getDeclarationWithValue());\r
+                       } else {\r
+                               // Continuous => Parent module takes care of declaring a value for the input\r
+                               b.append(i.getDeclaration());\r
+                       }\r
+               }\r
+       }\r
+\r
+       public String escape(String name) {\r
+               return name.replace(' ', '_');\r
+       }\r
+       \r
+       public static final String DELAY_TIME = "delayTime";\r
+       public static final String DELAY_INITIAL = "initialValue";\r
+\r
+       private static String getDelayClass(int order) {\r
+               StringBuilder buffer = new StringBuilder();\r
+\r
+               buffer.append("class " + getDelayName(order) + "\n");\r
+\r
+               // variable block\r
+\r
+               // (possibly) continuous auxiliary variable\r
+               buffer.append("\tReal DL;\n");\r
+               // (possibly) continuous delay time\r
+               buffer.append("\tReal " + DELAY_TIME + ";\n");\r
+               // (possibly) continuous initial value\r
+               buffer.append("\tReal " + DELAY_INITIAL + ";\n");\r
+\r
+               // first valve\r
+               buffer.append("\tReal " + getDelayValve(0) + ";\n");\r
+\r
+               // stocks and valves, valves are delayed values of the variable\r
+               for (int i = 1; i <= order; i++) {\r
+                       buffer.append("\tReal LV"+i + "(fixed=false);\n");\r
+                       buffer.append("\tReal "+ getDelayValve(i) + ";\n");\r
+               }\r
+\r
+               // initial equation block\r
+               buffer.append("initial equation\n");\r
+\r
+               // Each stock gets the same initial value\r
+               for (int i = 1; i <= order; i++) {\r
+                       buffer.append("\tLV"+i + " = DL * " + DELAY_INITIAL + ";\n");\r
+               }\r
+\r
+               // equation block\r
+               buffer.append("equation\n");\r
+               \r
+               buffer.append("\tDL = " + DELAY_TIME + " / "+order+";\n");\r
+\r
+               // valves and stocks\r
+               for (int i = 1; i <= order; i++) {\r
+                       buffer.append("\tder(LV"+i + ") = - " + getDelayValve(i) + " + " + getDelayValve(i-1) + ";\n");\r
+                       buffer.append("\t"+ getDelayValve(i) + " = LV"+i + " / DL;\n");\r
+               }\r
+\r
+               buffer.append("end ");\r
+               buffer.append(getDelayName(order));\r
+               buffer.append(";\n");\r
+\r
+               return buffer.toString();\r
+       }\r
+\r
+       public static String getDelayName(int order) {\r
+               return "order_"+order+"_delay";\r
+       }\r
+       \r
+       public static String getDelayValve(int order) {\r
+               return "delay"+order;\r
+       }\r
 \r
 }\r