001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/graphics/legend/LegendFactory.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003     
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010     
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015     
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020     
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024     
025     Contact:
026     
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53115 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033     
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041     
042     
043     ---------------------------------------------------------------------------*/
044    package org.deegree.graphics.legend;
045    
046    import java.awt.image.BufferedImage;
047    import java.util.ArrayList;
048    import java.util.List;
049    
050    import org.deegree.framework.log.ILogger;
051    import org.deegree.framework.log.LoggerFactory;
052    import org.deegree.graphics.sld.AbstractStyle;
053    import org.deegree.graphics.sld.FeatureTypeStyle;
054    import org.deegree.graphics.sld.Rule;
055    import org.deegree.graphics.sld.StyledLayerDescriptor;
056    import org.deegree.graphics.sld.UserStyle;
057    import org.deegree.model.filterencoding.ComplexFilter;
058    import org.deegree.model.filterencoding.Filter;
059    import org.deegree.model.filterencoding.Literal;
060    import org.deegree.model.filterencoding.LogicalOperation;
061    import org.deegree.model.filterencoding.Operation;
062    import org.deegree.model.filterencoding.OperationDefines;
063    import org.deegree.model.filterencoding.PropertyIsCOMPOperation;
064    import org.deegree.model.filterencoding.PropertyIsLikeOperation;
065    import org.deegree.model.filterencoding.PropertyName;
066    import org.deegree.model.filterencoding.SpatialOperation;
067    
068    /**
069     * factory class for creating legend elements/images to be used with WMS GetLegendGraphic request
070     * 
071     * @version $Revision: 9340 $
072     * @author $author$
073     */
074    public class LegendFactory {
075    
076        private static final ILogger LOG = LoggerFactory.getLogger( LegendFactory.class );
077    
078        private String label = "";
079    
080        private String legendtitle = "";
081    
082        /**
083         * creates a <tt>LegendElement</tt> using the passed <tt>BufferedImage</tt>
084         * 
085         * @return <tt>LegendElement</tt>
086         */
087        public LegendElement createLegendElement( BufferedImage legendImage ) {
088            return new LegendElement( legendImage );
089        }
090    
091        /**
092         * creates a <tt>LegendElement</tt> from a SLD <tt>Style</tt>. Depending on the
093         * <tt>Style</tt> the returned <tt>LegendElement</tt> may is a
094         * <tt>LegendElementCollection</tt>.
095         * 
096         * @return <tt>LegendElement</tt>
097         */
098        public LegendElement createLegendElement( AbstractStyle style, int width, int height,
099                                                 String title ) throws LegendException {
100    
101            setLegendTitle( title );
102    
103            if ( style instanceof UserStyle ) {
104    
105                LegendElement le = null;
106    
107                FeatureTypeStyle[] fts = ( (UserStyle) style ).getFeatureTypeStyles();
108                LegendElementCollection lec = new LegendElementCollection();
109    
110                for ( int a = 0; a < fts.length; a++ ) {
111                    // legendtitle
112                    if ( title != null && title.length() > 0 ) {
113                        if ( ( (UserStyle) style ).getTitle() != null ) {
114                            setLegendTitle( title );
115                        } else {
116                            setLegendTitle( title );
117                        }
118                    } else {
119                        setLegendTitle( fts[a].getName() );
120                    }
121                    Rule[] rules = fts[a].getRules();
122    
123                    for ( int b = 0; b < rules.length; b++ ) {
124    
125                        if ( rules[b].getFilter() != null ) {
126                            Filter f = rules[b].getFilter();
127                            String category = rules[b].getTitle();
128                            if ( category == null ) {
129                                category = rules[b].getName();
130                            }
131                            if ( category == null ) {
132                                category = getPropertyNameFromFilter( f );
133                            }
134                            le = new LegendElement( new Rule[] { rules[b] }, category, 0, 4, true,
135                                                    width, height );
136                            lec.addLegendElement( le );
137                        } else {
138                            String category = ( (UserStyle) style ).getTitle();
139                            if ( category == null ) {
140                                category = ( (UserStyle) style ).getName();
141                            }
142                            if ( category == null ) {
143                                category = title;
144                            }
145                            category = "";
146                            le = new LegendElement( rules, category, 0, 4, true, width, height );
147                        }
148                    }
149                }
150    
151                if ( lec.getSize() >= 1 ) {
152                    lec.setTitle( getLegendTitle() );
153                    return lec;
154                }
155                return le;
156            }
157            throw new LegendException( "LegendFactory: Error in creating the LegendElement:\n"
158                                       + "Given style is not a valid UserStyle." );
159        }
160    
161        /**
162         * creates an empty <tt>LegendElementCollection</tt>
163         * 
164         * @return <tt>LegendElementCollection</tt>
165         */
166        public LegendElementCollection createLegendElementCollection() {
167            return new LegendElementCollection();
168        }
169    
170        /**
171         * creates a <tt>LegendElementCollection</tt> and fills it with the passed
172         * <tt>LegendElement</tt>s.
173         * 
174         * @return <tt>LegendElementCollection</tt>
175         */
176        public LegendElementCollection createLegendElementCollection( LegendElement[] legendElements ) {
177            LegendElementCollection lec = new LegendElementCollection();
178    
179            for ( int i = 0; i < legendElements.length; i++ ) {
180                lec.addLegendElement( legendElements[i] );
181            }
182            return lec;
183        }
184    
185        /**
186         * 
187         * @param sld
188         * @param width
189         * @param height
190         * @return
191         * @throws LegendException
192         */
193        public BufferedImage[] createAllThumbnails( StyledLayerDescriptor sld, int width, int height,
194                                                   String mime ) throws LegendException {
195    
196            List<AbstractStyle> list = new ArrayList<AbstractStyle>();
197    
198            org.deegree.graphics.sld.AbstractLayer[] nl = sld.getNamedLayers();
199            for ( int i = 0; i < nl.length; i++ ) {
200                AbstractStyle[] styles = nl[i].getStyles();
201                for ( int j = 0; j < styles.length; j++ ) {
202                    if ( styles[j] instanceof UserStyle ) {
203                        list.add( styles[j] );
204                    }
205                }
206            }
207    
208            nl = sld.getUserLayers();
209            for ( int i = 0; i < nl.length; i++ ) {
210                AbstractStyle[] styles = nl[i].getStyles();
211                for ( int j = 0; j < styles.length; j++ ) {
212                    if ( styles[j] instanceof UserStyle ) {
213                        list.add( styles[j] );
214                    }
215                }
216            }
217    
218            LegendElement le = null;
219            BufferedImage bi_temp = null; // just temporary
220            BufferedImage[] buffi = new BufferedImage[list.size()]; // @return
221    
222            for ( int i = 0; i < list.size(); i++ ) {
223                AbstractStyle style = list.get( i );
224                String name = style.getName();
225                name = name.replace( ':', '_' );
226                LOG.logInfo( "creating: " + name );
227                le = createLegendElement( style, width, height, "" );
228                bi_temp = le.exportAsImage( mime );
229                buffi[i] = bi_temp;
230            }
231    
232            return buffi;
233        }
234    
235        /**
236         * gets the property-names for creating the legend text
237         */
238        private String getPropertyNameFromFilter( Filter filter ) throws LegendException {
239            ComplexFilter cf = (ComplexFilter) filter;
240    
241            LOG.logDebug( "Name der Operation: " + cf.getOperation().getOperatorName() + "\n"
242                          + cf.toXML() );
243            Operation operation = cf.getOperation();
244            String ret = getPropertyNameFromOperation( operation );
245            return ret;
246    
247        }
248    
249        /**
250         * 
251         * @param operation
252         * @return
253         * @throws LegendException
254         */
255        private String getPropertyNameFromOperation( Operation operation ) throws LegendException {
256    
257            String legendlabel = "";
258    
259            // determines the operation
260            // IS COM
261            if ( operation instanceof PropertyIsCOMPOperation ) {
262                PropertyIsCOMPOperation pCOMPo = (PropertyIsCOMPOperation) operation;
263                // gets the PropertyName of the operation for creating a legendtitle
264                if ( pCOMPo.getFirstExpression() instanceof PropertyName ) {
265                    PropertyName propertyname = (PropertyName) pCOMPo.getFirstExpression();
266                    // setLegendTitleFilterProperty(propertyname.getValue());
267                    legendlabel += propertyname.getValue();
268                } else {
269                    throw new LegendException( "LegendElement_Impl: An error occured "
270                                               + "during the parsing of the Filter in the SLD."
271                                               + "First Operation Expression is not of type Literal" );
272                }
273                legendlabel += getOperationString( pCOMPo.getOperatorId() );
274                // gets the Literal of the operation
275                if ( pCOMPo.getSecondExpression() instanceof Literal ) {
276                    Literal literal = (Literal) pCOMPo.getSecondExpression();
277                    legendlabel += literal.getValue();
278                } else {
279                    throw new LegendException( "LegendElement_Impl: An error occured "
280                                               + "during the parsing of the Filter in the SLD."
281                                               + "Second Operation Expression is not of type Literal" );
282                }
283                // LOGICAL
284            } else if ( operation instanceof LogicalOperation ) {
285                LogicalOperation logOp = (LogicalOperation) operation;
286                String operatorstring = getOperationString( logOp.getOperatorId() );
287    
288                // Operator-ID: AND = 200, OR = 201, NOT = 202
289                if ( logOp.getOperatorId() == OperationDefines.AND ) {
290                    List<Operation> andlist = logOp.getArguments();
291                    String andstring = "";
292                    for ( int i = 0; i < andlist.size(); i++ ) {
293                        andstring += getPropertyNameFromOperation( andlist.get( i ) );
294                        if ( i < andlist.size() - 1 ) {
295                            andstring += operatorstring;
296                        }
297                    }
298                    legendlabel = andstring;
299                } else if ( logOp.getOperatorId() == OperationDefines.OR ) {
300                    List<Operation> orlist = logOp.getArguments();
301                    String orstring = "";
302                    for ( int i = 0; i < orlist.size(); i++ ) {
303                        orstring += getPropertyNameFromOperation( orlist.get( i ) );
304                        if ( i < orlist.size() - 1 ) {
305                            orstring += operatorstring;
306                        }
307                    }
308                    legendlabel = orstring;
309                } else if ( logOp.getOperatorId() == OperationDefines.NOT ) {
310                    List<Operation> notlist = logOp.getArguments();
311                    String notstring = getPropertyNameFromOperation( notlist.get( 0 ) );
312                    // not is followed by brackets: not (ID = 1 and ID = 2)
313                    legendlabel = operatorstring + "(" + notstring + ")";
314                }
315    
316                // SPATIAL
317            } else if ( operation instanceof SpatialOperation ) {
318    
319                SpatialOperation spatop = (SpatialOperation) operation;
320    
321                legendlabel = "spatial operation" + spatop;
322                // PROPERTY IS LIKE
323            } else if ( operation instanceof PropertyIsLikeOperation ) {
324    
325                PropertyIsLikeOperation prilop = (PropertyIsLikeOperation) operation;
326    
327                legendlabel = prilop.getPropertyName().getValue()
328                              + getOperationString( prilop.getOperatorId() )
329                              + prilop.getLiteral().getValue();
330                // LOGICAL
331            } else {
332                LOG.logWarning( operation.toString() );
333                // TODO implement other filter-operations and ELSE!
334                throw new LegendException( "Filter-Operation <" + operation.getOperatorName()
335                                           + "> is no PropertyIsCOMPOperation." );
336            }
337    
338            return legendlabel;
339    
340        }
341    
342        /**
343         * 
344         * @param operationID
345         * @return
346         */
347        private String getOperationString( int operationID ) {
348            String operationString = "";
349    
350            switch ( operationID ) {
351            case OperationDefines.PROPERTYISEQUALTO:
352                operationString = " = ";
353                break;
354            case OperationDefines.PROPERTYISLESSTHAN:
355                operationString = " < ";
356                break;
357            case OperationDefines.PROPERTYISGREATERTHAN:
358                operationString = " > ";
359                break;
360            case OperationDefines.PROPERTYISLESSTHANOREQUALTO:
361                operationString = " <= ";
362                break;
363            case OperationDefines.PROPERTYISGREATERTHANOREQUALTO:
364                operationString = " >=  ";
365                break;
366            case OperationDefines.PROPERTYISLIKE:
367                operationString = " is like ";
368                break;
369            case OperationDefines.PROPERTYISNULL:
370                operationString = " is NULL ";
371                break;
372            case OperationDefines.PROPERTYISBETWEEN:
373                operationString = " is between ";
374                break;
375            case OperationDefines.AND:
376                operationString = " and ";
377                break;
378            case OperationDefines.OR:
379                operationString = " or ";
380                break;
381            case OperationDefines.NOT:
382                operationString = " not ";
383                break;
384            }
385    
386            return operationString;
387        }
388    
389        /**
390         * sets the label of the <tt>LegendElement</tt>
391         * 
392         * @param label
393         *            label of the <tt>LegendElement</tt>
394         * 
395         */
396        public void setLabel( String label ) {
397            this.label = label;
398        }
399    
400        /**
401         * returns the label set to <tt>LegendElement</tt>. If no label is set, the method returns
402         * <tt>null</tt>
403         * 
404         * @return label of the <tt>LegendElement</tt> or <tt>null</tt>
405         * 
406         */
407        public String getLabel() {
408            return this.label;
409        }
410    
411        /**
412         * @return
413         */
414        protected String getLegendTitle() {
415            return this.legendtitle;
416        }
417    
418        /**
419         * @param string
420         */
421        private void setLegendTitle( String string ) {
422            this.legendtitle = string;
423        }
424    
425    
426    }