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