View Javadoc
1   /*
2    * Themis: Java Project Framework
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.themis.solver.proj;
18  
19  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
20  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
21  import io.github.tonywasher.joceanus.themis.parser.base.ThemisChar;
22  import io.github.tonywasher.joceanus.themis.parser.base.ThemisDataResource;
23  import io.github.tonywasher.joceanus.themis.parser.project.ThemisModule;
24  import io.github.tonywasher.joceanus.themis.parser.project.ThemisPackage;
25  import io.github.tonywasher.joceanus.themis.solver.proj.ThemisSolverDef.ThemisSolverModuleDef;
26  import io.github.tonywasher.joceanus.themis.solver.proj.ThemisSolverDef.ThemisSolverProjectDef;
27  
28  import java.util.ArrayList;
29  import java.util.HashMap;
30  import java.util.LinkedHashMap;
31  import java.util.List;
32  import java.util.Map;
33  
34  /**
35   * Solver Module.
36   */
37  public class ThemisSolverModule
38          implements ThemisSolverModuleDef {
39      /**
40       * Report fields.
41       */
42      private static final MetisFieldSet<ThemisSolverModule> FIELD_DEFS = MetisFieldSet.newFieldSet(ThemisSolverModule.class);
43  
44      /*
45       * Declare Fields.
46       */
47      static {
48          FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_PROJECT, ThemisSolverModule::getOwningProject);
49          FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_PACKAGES, ThemisSolverModule::getPackages);
50          FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_UNDERLYING, ThemisSolverModule::getUnderlyingModule);
51      }
52  
53      /**
54       * The root package.
55       */
56      public static final String ROOT = "";
57  
58      /**
59       * The owning project.
60       */
61      private final ThemisSolverProjectDef theProject;
62  
63      /**
64       * The underlying module.
65       */
66      private final ThemisModule theModule;
67  
68      /**
69       * The list of packages.
70       */
71      private final Map<String, ThemisSolverPackage> thePackages;
72  
73      /**
74       * Constructor.
75       *
76       * @param pProject the owning project
77       * @param pModule  the parsed module
78       */
79      ThemisSolverModule(final ThemisSolverProjectDef pProject,
80                         final ThemisModule pModule) {
81          /* Store the parameters */
82          theProject = pProject;
83          theModule = pModule;
84  
85          /* Initialise the packages */
86          thePackages = new LinkedHashMap<>();
87          for (ThemisPackage myPackage : theModule.getPackages()) {
88              final ThemisSolverPackage mySolverPackage = new ThemisSolverPackage(this, myPackage);
89              thePackages.put(mySolverPackage.getPackageName(), mySolverPackage);
90          }
91  
92          /* Create placeHolders*/
93          createPlaceHolders();
94      }
95  
96      @Override
97      public MetisFieldSet<ThemisSolverModule> getDataFieldSet() {
98          return FIELD_DEFS;
99      }
100 
101     @Override
102     public String formatObject(final OceanusDataFormatter pFormatter) {
103         return toString();
104     }
105 
106     @Override
107     public ThemisSolverProjectDef getOwningProject() {
108         return theProject;
109     }
110 
111     @Override
112     public ThemisModule getUnderlyingModule() {
113         return theModule;
114     }
115 
116     /**
117      * Obtain the packages.
118      *
119      * @return the packages
120      */
121     public Map<String, ThemisSolverPackage> getPackages() {
122         return thePackages;
123     }
124 
125     @Override
126     public String toString() {
127         return theModule.toString();
128     }
129 
130     /**
131      * Is this package in error?
132      *
133      * @return true/false
134      */
135     public boolean isInError() {
136         final ThemisSolverPackage myRoot = getRoot();
137         return myRoot != null && myRoot.isInError();
138     }
139 
140     /**
141      * Create placeHolder packages.
142      */
143     private void createPlaceHolders() {
144         /* Create a list and map of real packages */
145         final HashMap<String, ThemisSolverPackage> myPackageMap = new HashMap<>(thePackages);
146         final List<ThemisSolverPackage> myPackages = new ArrayList<>(thePackages.values());
147 
148         /* Loop through the full packages */
149         for (ThemisSolverPackage myPackage : myPackages) {
150             /* Add the parent link */
151             addParentLink(myPackageMap, myPackage);
152         }
153     }
154 
155     /**
156      * Create placeHolder packages.
157      *
158      * @param pPackageMap the referenceMap
159      * @param pPackage    the package
160      */
161     private void addParentLink(final Map<String, ThemisSolverPackage> pPackageMap,
162                                final ThemisSolverPackage pPackage) {
163         /* Determine name of parent package */
164         final String myName = pPackage.getPackageName();
165         final int iIndex = myName.lastIndexOf(ThemisChar.PERIOD);
166         final String myParentName = iIndex == -1 ? ROOT : myName.substring(0, iIndex);
167 
168         /* Look up parent */
169         ThemisSolverPackage myParent = pPackageMap.get(myParentName);
170 
171         /* If we did not find a parent */
172         if (myParent == null) {
173             /* Create a placeholder parent and put into maps */
174             myParent = new ThemisSolverPackage(this, new ThemisPackage(myParentName));
175             pPackageMap.put(myParentName, myParent);
176             thePackages.put(myParentName, myParent);
177 
178             /* Add further links if we have not reached ROOT */
179             if (!ROOT.equals(myParentName)) {
180                 addParentLink(pPackageMap, myParent);
181             }
182         }
183 
184         /* Add child to parent */
185         myParent.addChild(pPackage);
186     }
187 
188     /**
189      * Look for packages that are immediate roots.
190      *
191      * @return the immediate roots
192      */
193     public ThemisSolverPackage getRoot() {
194         /* Return the root */
195         return thePackages.get(ROOT);
196     }
197 }