001    package hirondelle.web4jtools.metrics.images;
002    
003    import static hirondelle.web4j.util.Consts.NOT_FOUND;
004    import hirondelle.web4j.action.ResponsePage;
005    import hirondelle.web4j.request.RequestParameter;
006    import hirondelle.web4j.request.RequestParser;
007    import hirondelle.web4j.util.Util;
008    import hirondelle.web4jtools.metrics.base.FileInfo;
009    import hirondelle.web4jtools.metrics.base.MetricsAction;
010    
011    import java.util.ArrayList;
012    import java.util.Collections;
013    import java.util.Comparator;
014    import java.util.List;
015    ;
016    
017    /**
018    * List all images in the target project, along with all references to each image occurring in 
019    * markup files.
020    * Any image having 0 references are candidates for removal from the project. 
021    */
022    public class ImageReferencesAction extends MetricsAction {
023    
024      /** Full constructor. */
025      public ImageReferencesAction(RequestParser aRequestParser){
026        super(FORWARD, aRequestParser);
027      }
028      
029      /** The column of the listing to sort on. See the <tt>sortLinks.tag</tt> file. */
030      public static final RequestParameter SORT_ON = RequestParameter.withRegexCheck("SortOn", "(Name|NumReferences|Bytes)");
031      /** Ascending or descending order. See the <tt>sortLinks.tag</tt> file. */
032      public static final RequestParameter ORDER = RequestParameter.withRegexCheck("Order", "(ASC|DESC)");
033      
034      /** 
035      * Show a sortable listing of images and the files that reference them.
036      * The default sort is by the number of references.
037      */
038      @Override  protected void calculateMetric() {
039        List<ImageReference> imgRefs = new ArrayList<ImageReference>();
040        List<FileInfo> imageFiles = filterImageFiles();
041        List<FileInfo> markupFiles = filterMarkupFiles();
042        initializeImageReferences(imgRefs, imageFiles);
043    
044        for(FileInfo markupFile : markupFiles){
045          String markupFileContent = markupFile.getContent();
046          for (FileInfo imageFile : imageFiles) {
047            if( hasImageReference(markupFileContent, imageFile)){
048              addImageReference(markupFile, imageFile, imgRefs);
049            }
050          }
051        }
052        sort(imgRefs);
053        addToRequest("imgReferences", imgRefs);
054      }
055      
056      
057      // PRIVATE //
058      private static final ResponsePage FORWARD = new ResponsePage("Images and Their References", "view.jsp", ImageReferencesAction.class);
059      
060      private List<FileInfo> filterImageFiles() {
061        List<FileInfo> result = new ArrayList<FileInfo>();
062        for(FileInfo file : fFileList){
063          if ( file.isImageFile() ) {
064            result.add(file);
065          }
066        }
067        return result;
068      }
069      
070      private List<FileInfo> filterMarkupFiles() {
071        List<FileInfo> result = new ArrayList<FileInfo>();
072        for(FileInfo file : fFileList){
073          if ( file.isMarkupFile() ) {
074            result.add(file);
075          }
076        }
077        return result;
078      }
079      
080      private void  initializeImageReferences(List<ImageReference> aImgRefs, List<FileInfo> aImageFiles){
081        for(FileInfo imageFile : aImageFiles)  {
082          aImgRefs.add(new ImageReference(imageFile));
083        }
084      }
085      
086      /**
087      * This check is a bit simplistic, since it does not use path information at all. 
088      * It only checks if the file contains the simple image file name, anywhere in its 
089      * body, without using the full path of the image file. 
090      * 
091      * <P>This style at least allows for referencing image files in many different ways.
092      */
093      private boolean hasImageReference(String aMarkupFileContent, FileInfo aImageFile){
094        return aMarkupFileContent.indexOf(aImageFile.getSimpleName().getRawString()) != NOT_FOUND;
095      }
096    
097      private void addImageReference(FileInfo aMarkupFile, FileInfo aImageFile, List<ImageReference> aImgRefs) {
098        ImageReference imageRef = null;
099        for (ImageReference item : aImgRefs){
100          if (item.getFileInfo().equals(aImageFile)) {
101            imageRef = item;
102            break;
103          }
104        }
105        if ( imageRef == null ) {
106          throw new AssertionError("Cannot find image file as expected.");
107        }
108        imageRef.addReferenceFrom(aMarkupFile);
109      }
110      
111      private void sort(List<ImageReference> aImgRefs) {
112        String sortOn = getParamUnsafe(SORT_ON);
113        String order = getParamUnsafe(ORDER);
114        Collections.sort(aImgRefs, getComparator(sortOn));
115        if( "DESC".equals(order) || ! Util.textHasContent(order)) {
116          Collections.reverse(aImgRefs);
117        }
118      }
119      
120      private Comparator<ImageReference> getComparator(String aSortOn){
121        Comparator<ImageReference> result = null;
122        if( "Name".equals(aSortOn)  ) {
123          result = new Comparator<ImageReference>() {
124            public int compare(ImageReference aThis, ImageReference aThat) {
125              String thisName = aThis.getFileInfo().getSimpleName().getRawString();
126              String thatName = aThat.getFileInfo().getSimpleName().getRawString();
127              return thisName.compareTo(thatName);
128            };
129          };
130        }
131        if( "Bytes".equals(aSortOn)  ) {
132          result = new Comparator<ImageReference>() {
133            public int compare(ImageReference aThis, ImageReference aThat) {
134              Long thisSize = aThis.getFileInfo().getSize();
135              Long thatSize = aThat.getFileInfo().getSize();
136              return thisSize.compareTo(thatSize);
137            };
138          };
139        }
140        //default sorting by num references
141        else if ( "NumReferences".equals(aSortOn) || ! Util.textHasContent(aSortOn) ) {
142          result = new Comparator<ImageReference>() {
143            public int compare(ImageReference aThis, ImageReference aThat) {
144              return aThis.getNumReferences().compareTo(aThat.getNumReferences());
145            };
146          };
147        }
148        else {
149          throw new AssertionError("Unknown sort column : " + Util.quote(aSortOn));
150        }
151        return result;
152      }
153    }