001/****************************************************************************
002 * Copyright/Copyleft:
003 *
004 * For this source the LGPL Lesser General Public License,
005 * published by the Free Software Foundation is valid.
006 * It means:
007 * 1) You can use this source without any restriction for any desired purpose.
008 * 2) You can redistribute copies of this source to everybody.
009 * 3) Every user of this source, also the user of redistribute copies
010 *    with or without payment, must accept this license for further using.
011 * 4) But the LPGL is not appropriate for a whole software product,
012 *    if this source is only a part of them. It means, the user
013 *    must publish this part of source,
014 *    but don't need to publish the whole source of the own product.
015 * 5) You can study and modify (improve) this source
016 *    for own using or for redistribution, but you have to license the
017 *    modified sources likewise under this LGPL Lesser General Public License.
018 *    You mustn't delete this Copyright/Copyleft inscription in this source file.
019 *
020 * @author Hartmut Schorrig: hartmut.schorrig@vishia.de, www.vishia.org
021 * @version 0.93 2011-01-05  (year-month-day)
022 *******************************************************************************/ 
023package org.vishia.java2C;
024
025import java.io.File;
026import java.text.ParseException;
027import java.util.Iterator;
028import java.util.LinkedList;
029import java.util.List;
030import java.util.Set;
031import java.util.TreeMap;
032import java.util.Map;
033
034import org.vishia.mainCmd.Report;
035import org.vishia.util.SortedTree;
036
037/**Representation of an existing Folder in the Java pkg tree.
038 */
039public class JavaSrcTreePkg implements SortedTree<JavaSrcTreePkg>, JavaSources.ClassDataOrJavaSrcFile
040{
041  
042  /**Version, history and license.
043   * <ul>
044   * <li>2014-09-05 Hartmut chg: {@link #setFileJava(String, File, String, org.vishia.java2C.ConfigSrcPathPkg_ifc.Set, String, boolean)} not used arguments removed.
045   *   The arguments <code>String prefixCFile, String suffixCFile, String prefixNames, String suffixNames</code> are contained 
046   *   in the <code>ConfigSrcPathPkg_ifc.Set info</code> already.
047   * <li>2014-09-05 Hartmut new: {@link #setFileAndReadStcFile(String, org.vishia.java2C.ConfigSrcPathPkg_ifc.Set, String)}. This is one method which reads
048   *   all information about a Java class from a existing stc file, especially used for C-written parts read in {@link CRuntimeJavalikeClassData}.  
049   * <li>2008 Hartmut created:    
050   * </ul>
051   * <br><br>
052   * <b>Copyright/Copyleft</b>:
053   * For this source the LGPL Lesser General Public License,
054   * published by the Free Software Foundation is valid.
055   * It means:
056   * <ol>
057   * <li> You can use this source without any restriction for any desired purpose.
058   * <li> You can redistribute copies of this source to everybody.
059   * <li> Every user of this source, also the user of redistribute copies
060   *    with or without payment, must accept this license for further using.
061   * <li> But the LPGL is not appropriate for a whole software product,
062   *    if this source is only a part of them. It means, the user
063   *    must publish this part of source,
064   *    but don't need to publish the whole source of the own product.
065   * <li> You can study and modify (improve) this source
066   *    for own using or for redistribution, but you have to license the
067   *    modified sources likewise under this LGPL Lesser General Public License.
068   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
069   * </ol>
070   * If you are intent to use this sources without publishing its usage, you can get
071   * a second license subscribing a special contract with the author. 
072   * 
073   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
074   */
075  public final static String sVersion = "2014-09-05"; 
076
077  private final String sPkgPath;
078  
079  private final String sPkgName;
080  
081  /**The parent pkg, it is only to see in debug and reports.*/
082  private final JavaSrcTreePkg parent; 
083  
084  private TreeMap<String, JavaSrcTreePkg> subPkgs;
085  
086  /**All file.java containing in this package. */
087  private final TreeMap<String, JavaSrcTreeFile> XXXjavaFiles = new TreeMap<String, JavaSrcTreeFile>();
088
089  
090  /**Same content as {@link #javaFiles}, but the key is the class name. */
091  //private final TreeMap<String, JavaSrcTreeFile> javaPublicClasses = new TreeMap<String, JavaSrcTreeFile>();
092  private final List<JavaSources.ClassDataOrJavaSrcFile> javaPublicClasses = new LinkedList<JavaSources.ClassDataOrJavaSrcFile>();
093  
094  /**Set to true if {@link #setFileJava(String, File, String, String, String, boolean)}
095   * is called the first time. */
096  private boolean pkgHasFiles = false;
097  
098  /**If this info is found, a stc-file is determined for the package to replace structure info
099   * instead given Java-files.
100   */
101  private ConfigSrcPathPkg_ifc.Set replaceCinfo;
102  
103  /**Index of all sub-packages and classes available in the package, package privates too. 
104   * Only the field {@link LocalIdents#typeIdents} is used, because a package has no fields. 
105   * But the type {@link LocalIndents} is necessary to implement 
106   * the method {@link JavaSources.ClassDataOrJavaSrcFile#getLocalIdents(String)}
107   * to support getting data to an identifier inside the package (may be sub-package or a file or a class known in package).
108   */
109  private final LocalIdents pkgIdents;
110
111  
112  /**
113   * @param pkgIdent
114   * @param javaSrcPath
115   */
116  public JavaSrcTreePkg(JavaSrcTreePkg parent, String pkgPath, String pkgName, ConfigSrcPathPkg_ifc.Set replaceCinfo) //, LocalIdents identsToAssignPkgIdents)
117  { this.parent = parent;
118        this.sPkgPath = pkgPath;
119    this.sPkgName = pkgName;
120    this.replaceCinfo = replaceCinfo; //maybe null
121    pkgIdents = new LocalIdents(parent ==null ? null : parent.getPkgLevelIdents(), null);
122  }
123  
124  
125
126  /**returns the Instance, which represents the given package name. 
127   * If the Instance doesn't exist, it is created.
128   * If it exists already before this call, and its {@link #replaceCinfo} is null, 
129   * then the given parameter replaceCinfo is used to set it. 
130   * If the {@link #replaceCinfo} was given before, and the parameter replaceCinfo is given here too,
131   * it is tested whether it contains the same. Elsewhere a IllegalArgumentException is thrown.
132   * 
133   * @param pkgPath The full path from root
134   * @param pkgName The name of the new package
135   * @param replaceCinfo if not null, then it is the info to build the C-files /search the stc-file
136   *                     for all non-existing, but needed Java-files of the package. 
137   * @return The package management instance. 
138   */
139  public JavaSrcTreePkg getOrAddPkg(String pkgPath, String pkgName, ConfigSrcPathPkg_ifc.Set replaceCinfo) //, LocalIdents identsToAssignPkgIdents)
140  {
141        JavaSrcTreePkg ret;
142        if(subPkgs == null){ 
143        subPkgs = new TreeMap<String, JavaSrcTreePkg>(); 
144      ret = null;
145    } else {
146        ret = subPkgs.get(pkgName);  //try, maybe not found
147    }
148    if(ret == null){
149      ret = new JavaSrcTreePkg(this, pkgPath, pkgName, replaceCinfo); //, identsToAssignPkgIdents);
150      Java2C_Main.singleton.javaSources.indexJavaSrcPkgs.put(pkgPath, ret);
151      subPkgs.put(pkgName,ret);
152      //javaPublicClasses.putClassType(pkgName, ret);
153      this.pkgIdents.putClassType(pkgName, ret);   //to find as identifier while translating.
154    } else {
155        //found, check to replace the replaceCinfo
156        if(replaceCinfo != null){
157                //maybe todo: check whether it is the same info, not only null-check
158                if(ret.replaceCinfo != null) throw new IllegalArgumentException("package: " + pkgName + " - second replaceinfo: " + replaceCinfo.toString());
159                ret.replaceCinfo = replaceCinfo;
160        }
161    }
162    return ret;
163  }
164  
165  /**Adds the given type info to the pkgIdents.
166   * @param data The type info.
167   */
168  public void putClassType(ClassData data){
169        pkgIdents.putClassType(data);
170  }
171  
172  
173  public String getPkgPath(){ return sPkgPath; }
174  
175  public final TreeMap<String, JavaSrcTreeFile> XXXgetJavaFiles(){
176
177        return XXXjavaFiles;
178  }
179
180
181
182  public final List<JavaSources.ClassDataOrJavaSrcFile> getPublicClasses()
183  {
184    return javaPublicClasses;
185  }
186
187
188
189  /**Adds all standard types to the package. This method will be called if any file is containing
190   * in the package. It means, the package is the immediate package of any class. 
191   * This method will be called too while creating a standard package (java.lang).
192   * @param types
193   */
194  public void xxxaddStdTypes(LocalIdents types)
195  {
196    //javaPublicClasses.putClassTypesAll(types);
197    pkgIdents.putClassTypesAll(types);
198  }
199  
200  
201  /**Registers the occurrence of a found Java file or set the {@link ConfigSrcPathPkg_ifc.Set}
202   * for an existing file without replaceCinfo 
203   * @param javaSrcPath The source path where the file is found. It may be null for Classes, which are presented by its stc file only.
204   * @param fileJava The File instance ready to the open source file. null if javaSrcPath ==null.
205   * @param sFileNameJava The file name without path but with extension <code>.java</code> without directories. The class Name if a stc file will be registered.
206   * @param info informations to find out where the C-file is found and which pre/suffix are valid.
207   * @param stcPath null or a special path where the stc-file is located.
208   * @param translateToC false than the file should not be translate to C,
209   *        instead the stc-file should be used any time. This is if it is a standard class 
210   *        or a users class, which is located in a library.
211   * @return
212   */
213  public JavaSources.ClassDataOrJavaSrcFile setFileJava(String javaSrcPath, File fileJava, String sFileNameJava
214                , ConfigSrcPathPkg_ifc.Set info, String stcPath
215  , boolean translateToC
216  )//(String javaSrcPath, File fileJava, String nameFileJava, String pkgPath, String pathC, boolean bToTranslateToC)
217  { JavaSources.ClassDataOrJavaSrcFile javaSrc;
218    if(!pkgHasFiles){
219      /** First call of this method, add all standard types at first. */
220      pkgHasFiles =true;
221    }
222        
223    //javaSrc = javaFiles.get(sFileNameJava);  //check whether the file is known yet.
224    String sJavaClass = sFileNameJava.substring(0, sFileNameJava.indexOf(".java"));
225    javaSrc = pkgIdents.getTypeInfo(sJavaClass, null);  //check whether the file is known yet.
226    if( javaSrc== null){
227      /**register only the first occurrence of a Java file. If the file is located more than one time,
228       * the first occurrence should be used.
229       */
230      javaSrc = new JavaSrcTreeFile( this, javaSrcPath, fileJava, sFileNameJava, info
231                                   , stcPath, translateToC);
232      /**assume that the file contains a public class and put the name in type list, without yet ClassData. */
233      javaPublicClasses.add(javaSrc);
234      //TODO: a first first pass is necessary, with parsing file, to get all classes.
235      //up to now: only one class per file.
236      //it is done already: pkgIdents.putClassType(javaSrc.getPublicClassName(), javaSrc);
237    }
238    else if(javaSrc instanceof ClassData){
239      //it isknown already, do nothing.
240      System.out.println("setFileJava unnecessary: " + sFileNameJava);
241    } else{
242        //The package replacements are set already.
243        //notice, that it is found and maybe to translate!
244        //The Java-file may be exist already therefore, it is created in package replacement.
245      JavaSrcTreeFile javaSrcFile = (JavaSrcTreeFile)javaSrc;
246        javaSrcFile.infoSecondFile(fileJava, translateToC);
247    }
248    return javaSrc;
249  }
250
251
252  
253  
254  
255  /**Registers a Java class inside the given package and reads the associated stc file. 
256   * @param sClassname The class name
257   * @param info info about the path to C files
258   * @param stcPath Path to stc-File, maybe null if the stc file has the same path then the associated C file with extension .stc.
259   * @return the ClassData. That ClassData are stored in this {@link #pkgIdents} too, using {@link LocalIdents#getType(String, LocalIdents)} to get it.
260   *   The return value is used inside {@link CRuntimeJavalikeClassData} if the ClassData are used there. 
261   * @throws ParseException on faulty stc file.
262   */
263  public ClassData setFileAndReadStcFile(String sClassname, ConfigSrcPathPkg_ifc.Set info, String stcPath) 
264  throws ParseException
265  { String sFileNameJava = sClassname + ".java";
266    setFileJava(null, null, sFileNameJava, info, stcPath, false);
267    ClassData ret = pkgIdents.getType(sClassname, null);   //this forces reading the stc file
268    return ret;
269  }
270  
271  
272  
273  
274  
275  public void reportClasses(Report report)
276  {
277        Set<Map.Entry<String, JavaSources.ClassDataOrJavaSrcFile>> entries = pkgIdents.getTypeSet();
278    for(Map.Entry<String, JavaSources.ClassDataOrJavaSrcFile> entry: entries){
279        JavaSources.ClassDataOrJavaSrcFile javaFile= entry.getValue();
280      report.reportln(Report.fineInfo, "  +- " + entry.getKey() + " = "+ (javaFile !=null ? javaFile.toString(): "???"));
281    }
282    
283  }
284  
285
286  public JavaSrcTreePkg getChild(String key)
287  { return subPkgs.get(key);
288  }
289
290  /**gets the pkg-level-idents. It contains all types which are known 
291   * at this package level (all files of package.). 
292   */
293  public LocalIdents getPkgLevelIdents(){ return pkgIdents; }
294
295  public Iterator<JavaSrcTreePkg> iterChildren()
296  {
297    // TODO Auto-generated method stub
298    return null;
299  }
300
301
302
303  public Iterator<JavaSrcTreePkg> iterChildren(String key)
304  {
305    // TODO Auto-generated method stub
306    return null;
307  }
308
309
310
311  public List<JavaSrcTreePkg> listChildren()
312  {
313    List<JavaSrcTreePkg> ret = new LinkedList<JavaSrcTreePkg>();
314    if(subPkgs != null){
315      Set<Map.Entry<String, JavaSrcTreePkg>> entries = subPkgs.entrySet();
316      for(Map.Entry<String, JavaSrcTreePkg> entry: entries){
317        JavaSrcTreePkg folder= entry.getValue();
318        ret.add(folder);
319      }
320    }  
321    return ret;
322  }
323
324
325
326  public List<JavaSrcTreePkg> listChildren(String key)
327  {
328    // TODO Auto-generated method stub
329    return null;
330  }
331
332
333
334  public ClassData getClassData()
335  {
336    return null;
337  }
338
339
340
341  /**Implements {@link JavaSources.ClassDataOrJavaSrcFile#getJavaSrc()}
342   */
343  public JavaSrcTreeFile getJavaSrc()
344  {
345    return null; // it isn't a JavaSrcTreeFile
346  }
347
348  /**Implements {@link JavaSources.ClassDataOrJavaSrcFile#getJavaPkg()}
349   */
350  public JavaSrcTreePkg getJavaPkg()
351  {
352    return this; 
353  }
354  
355
356
357
358  /**Returns the identifier of classes or packages, which are available in this package.
359   * It may be sub-package or a file or a class known in package.
360   * implements {@link org.vishia.java2C.JavaSources.ClassDataOrJavaSrcFile#getLocalIdents(java.lang.String)}
361   * @param sPkgName: It is ignored. 
362   */
363  @Override public LocalIdents getLocalIdents(String sPkgName)
364  {
365    return pkgIdents;
366  }
367  
368  /**Implements {@link JavaSources.ClassDataOrJavaSrcFile#getTypeName()}
369   */
370  public String getTypeName()
371  {
372    return sPkgName;
373  }
374  
375  @Override public String toString(){
376        return sPkgPath;
377        /*
378        StringBuilder ret = new StringBuilder(200);
379        ret.append(sPkgPath);
380        if(subPkgs != null){
381                ret.append(':').append(subPkgs.toString());
382        }
383        return ret.toString();
384        */ 
385  }
386
387
388
389        /* (non-Javadoc)
390         * @see org.vishia.java2C.JavaSources.ClassDataOrJavaSrcFile#getReplaceCinfo()
391         */
392        @Override
393        public org.vishia.java2C.ConfigSrcPathPkg_ifc.Set getReplaceCinfo() {
394                return replaceCinfo;
395        }
396
397
398
399        /**returns false because a package isn't to translate.
400         * @see org.vishia.java2C.JavaSources.ClassDataOrJavaSrcFile#isToTranslate()
401         */
402        @Override
403        public boolean isToTranslate() {
404                return false;
405        }  
406
407        @Override public void setClassData(ClassData data){
408        throw new IllegalArgumentException("internal: ClassData for package");
409  }
410
411
412
413  @Override
414  public JavaSrcTreePkg getParent() {
415    // TODO Auto-generated method stub
416    return null;
417  }
418
419  
420}