001package armyc2.c5isr.web.render.utilities;
002
003import armyc2.c5isr.renderer.utilities.DrawRules;
004import armyc2.c5isr.renderer.utilities.MSInfo;
005import armyc2.c5isr.renderer.utilities.MSLookup;
006import armyc2.c5isr.renderer.utilities.MilStdAttributes;
007import armyc2.c5isr.graphics2d.Point2D;
008import armyc2.c5isr.renderer.utilities.Modifiers;
009
010import java.io.PrintWriter;
011import java.io.StringWriter;
012import java.io.Writer;
013import java.util.HashMap;
014import java.util.Locale;
015import java.util.Map;
016
017/**
018 *
019*
020 */
021@SuppressWarnings("unused")
022public class JavaRendererUtilities {
023
024    public static final String HOSTILE_FILL_COLOR = "FFFF8080";
025    public static final String FRIENDLY_FILL_COLOR = "FF80E0FF";
026    public static final String NEUTRAL_FILL_COLOR = "FFAAFFAA";
027    public static final String UNKNOWN_FILL_COLOR = "FFFFFF80";
028
029    /**
030     * Converts ARGB string format to the Google used ABGR string format. Google
031     * reverses the blue and red positioning.
032     *
033     * @param rgbString A color string of the format AARRGGBB in hex value.
034     * @return the reverse of the input string in hex. The format should now be
035     * AABBGGRR
036     */
037    public static String ARGBtoABGR(String rgbString) {
038        if(rgbString.length()==6)
039        {
040            String s="FF";
041            rgbString=s.concat(rgbString);
042        }
043
044        String bgrString = rgbString.toUpperCase(Locale.US);
045        
046        if(rgbString.length() == 8)
047        {
048                char[] c = rgbString.toCharArray();
049                char temp1 = c[2];
050            char temp2 = c[3];
051            c[2] = c[6];
052            c[3] = c[7];
053            c[6] = temp1;
054            c[7] = temp2;
055            bgrString = new String(c);
056        }
057        else if(rgbString.length() == 6)
058        {
059                char[] c = rgbString.toCharArray();
060                char temp1 = c[0];
061            char temp2 = c[1];
062            c[0] = c[4];
063            c[1] = c[5];
064            c[4] = temp1;
065            c[5] = temp2;
066            bgrString = "FF" + new String(c);
067            //bgrString = "FF" + bgrString;
068        }
069        else
070        {
071                System.err.println("JavaRendererUtilties.ARGBtoABGR(): " + "\"" + String.valueOf(rgbString) + "\" is not a 6 or 8 character String in the format of RRGGBB or AARRGGBB");
072        }
073
074        return bgrString;
075    }
076
077    /**
078     * Returns a symbolId with just the identifiable symbol Id pieces. All
079     * variable information is returned as '*'. For example, a boundary,
080     * "GFGPGLB----KUSX" returns "G*G*GLB---****X";
081     *
082     * @param symbolCode A 15 character symbol ID.
083     * @return The normalized SymbolCode.
084     * @deprecated
085     */
086    public static String normalizeSymbolCode(String symbolCode) {
087
088        String newSymbolCode = symbolCode;
089
090        if (symbolCode.startsWith("G") || symbolCode.startsWith("S")) {
091            // Remove Affiliation
092            newSymbolCode = newSymbolCode.substring(0, 1) + '*' + newSymbolCode.substring(2);
093            // Remove planned/present field
094            newSymbolCode = newSymbolCode.substring(0, 3) + '*' + newSymbolCode.substring(4);
095            // Remove echelon, special code and country codes
096            newSymbolCode = newSymbolCode.substring(0, 10) + "****" + newSymbolCode.substring(14);
097        }
098
099        // If a unit replace last character with *.
100        if (symbolCode.startsWith("S")) {
101            newSymbolCode = newSymbolCode.substring(0, 14) + '*';
102        }
103
104        return newSymbolCode;
105    }
106    
107    public static void addAltModeToModifiersString(Map<String,String> attributes, String altMode)
108    {
109        if(altMode.equals("relativeToGround"))
110            attributes.put(MilStdAttributes.AltitudeMode, "AGL");
111        else if(altMode.equals("absolute"))
112                attributes.put(MilStdAttributes.AltitudeMode, "AMSL");
113    }
114
115    /**
116     *
117     * @param SymbolInfo something like
118     * "SymbolID?LineColor=0x000000&amp;FillColor=0xFFFFFF&amp;size=35"
119     */
120    public static Map<String, String> createParameterMapFromURL(String SymbolInfo) {
121        Map<String, String> modifiers = new HashMap<String, String>();
122        String symbolID = null;
123        String parameters = null;
124        String key = null;
125        String value = null;
126        String arrParameters[] = null;
127        String arrKeyValue[] = null;
128        String temp = null;
129        int questionIndex = SymbolInfo.lastIndexOf('?');
130
131        try {
132            if (questionIndex == -1) {
133                symbolID = java.net.URLDecoder.decode(SymbolInfo, "UTF-8");
134            } else {
135                symbolID = java.net.URLDecoder.decode(SymbolInfo.substring(0, questionIndex), "UTF-8");
136            }
137
138        } catch (Exception exc) {
139            System.err.println("Error parsing SymbolID");
140            System.err.println(exc.getMessage());
141        }
142
143        try {   //build a map for the other createMilstdSymbol function to use
144            //to build a milstd symbol.
145            if (questionIndex > 0 && (questionIndex + 1 < SymbolInfo.length())) {
146                parameters = SymbolInfo.substring(questionIndex + 1, SymbolInfo.length());
147                arrParameters = parameters.split("&");
148                int n = arrParameters.length;
149                //for(int i = 0; i < arrParameters.length; i++)
150                for (int i = 0; i < n; i++) {
151                    arrKeyValue = arrParameters[i].split("=");
152                    if (arrKeyValue.length == 2 && arrKeyValue[1] != null && arrKeyValue[1].equals("") == false) {
153
154                        key = arrKeyValue[0];
155                        value = arrKeyValue[1];
156
157                        temp = java.net.URLDecoder.decode(value, "UTF-8");
158                        modifiers.put(key.toUpperCase(), temp);
159
160                        //System.out.println("key: " + key + " value: " + temp);
161                    }
162                }
163            }
164        } catch (Exception exc) {
165            System.err.println("Error parsing \"" + key.toUpperCase() + "\" parameter from URL");
166            System.err.println(exc.getMessage());
167        }
168        return modifiers;
169    }
170
171    /*
172     * Try to turn a bad code into something renderable.
173     *
174     * @param symbolID
175     * @return
176     * @deprecated use SymbolUtilties.reconcileSymbolID() 9/5/2013
177     */
178    /*public static String ReconcileSymbolID(String symbolID) {
179        StringBuilder sb = new StringBuilder("");
180        char codingScheme = symbolID.charAt(0);
181
182        if (symbolID.length() < 15) {
183            while (symbolID.length() < 15) {
184                symbolID += "-";
185            }
186        }
187        if (symbolID.length() > 15) {
188            symbolID = symbolID.substring(0, 14);
189        }
190
191        if (symbolID != null && symbolID.length() == 15) {
192            if (codingScheme == 'S' || //warfighting
193                    codingScheme == 'I' ||//sigint
194                    codingScheme == 'O' ||//stability operation
195                    codingScheme == 'E')//emergency management
196            {
197                sb.append(codingScheme);
198
199                if (SymbolUtilities.hasValidAffiliation(symbolID) == false) {
200                    sb.append('U');
201                } else {
202                    sb.append(symbolID.charAt(1));
203                }
204
205                if (SymbolUtilities.hasValidBattleDimension(symbolID) == false) {
206                    sb.append('Z');
207                    sb.replace(0, 1, "S");
208                } else {
209                    sb.append(symbolID.charAt(2));
210                }
211
212                if (SymbolUtilities.hasValidStatus(symbolID) == false) {
213                    sb.append('P');
214                } else {
215                    sb.append(symbolID.charAt(3));
216                }
217
218                sb.append("------");
219                sb.append(symbolID.substring(10, 15));
220
221            } else if (codingScheme == 'G')//tactical
222            {
223                sb.append(codingScheme);
224
225                if (SymbolUtilities.hasValidAffiliation(symbolID) == false) {
226                    sb.append('U');
227                } else {
228                    sb.append(symbolID.charAt(1));
229                }
230
231                sb.append('G');
232
233                if (SymbolUtilities.hasValidStatus(symbolID) == false) {
234                    sb.append('P');
235                } else {
236                    sb.append(symbolID.charAt(3));
237                }
238
239                sb.append("GPP---");//return an action point
240                sb.append(symbolID.substring(10, 15));
241
242            } else if (codingScheme == 'W')//weather
243            {//no default weather graphic
244                return "SUZP-----------";//unknown
245            } else//bad codingScheme
246            {
247                sb.append('S');
248                if (SymbolUtilities.hasValidAffiliation(symbolID) == false) {
249                    sb.append('U');
250                } else {
251                    sb.append(symbolID.charAt(1));
252                }
253
254                if (SymbolUtilities.hasValidBattleDimension(symbolID) == false) {
255                    sb.append('Z');
256                } else {
257                    sb.append(symbolID.charAt(2));
258                }
259
260                if (SymbolUtilities.hasValidStatus(symbolID) == false) {
261                    sb.append('P');
262                } else {
263                    sb.append(symbolID.charAt(3));
264                }
265
266                sb.append("------");
267                sb.append(symbolID.substring(10, 15));
268            }
269        } else {
270            return "SUZP-----------";//unknown
271        }
272
273        return sb.toString();
274
275    }//*/
276
277    public static boolean is3dSymbol(String symbolCode) {
278        try {
279            MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolCode);
280            int drawRule = msi.getDrawRule();
281            return drawRule == DrawRules.AREA1
282                    || drawRule == DrawRules.AREA10
283                    || drawRule == DrawRules.RECTANGULAR1
284                    || drawRule == DrawRules.CIRCULAR1
285                    || drawRule == DrawRules.CORRIDOR1;
286        } catch (Exception e) {
287            System.err.println(e.getMessage());
288        }
289        return false;
290    }
291
292    /**
293     * Determines if a String represents a valid number
294     *
295     * @param text
296     * @return "1.56" == true, "1ab" == false
297     */
298    public static boolean isNumber(String text) {
299        if (text != null && text.matches("((-|\\+)?[0-9]+(\\.[0-9]+)?)+")) {
300            return true;
301        } else {
302            return false;
303        }
304    }
305
306    /**
307     * Takes a throwable and puts it's stacktrace into a string.
308     *
309     * @param thrown
310     * @return
311     */
312    public static String getStackTrace(Throwable thrown) {
313        try {
314            Writer writer = new StringWriter();
315            PrintWriter printWriter = new PrintWriter(writer);
316            thrown.printStackTrace(printWriter);
317            return writer.toString();
318        } catch (Exception exc) {
319            //System.out.println("JavaRendererUtilties.getStackTrace()");
320            //return "Error - couldn't retrieve stack trace";
321            return "";
322        }
323    }
324
325    public static Point2D getEndPointWithAngle(Point2D ptStart,
326                                               //Point2D pt1,
327                                               //Point2D pt2,
328                                               double angle,
329                                               double distance) {
330        double newX = 0;
331        double newY = 0;
332        Point2D pt = new Point2D.Double();
333        try {
334            //first get the angle psi between pt0 and pt1
335            double psi = 0;//Math.atan((pt1.y - pt0.y) / (pt1.x - pt0.x));
336            //double psi = Math.atan((ptStart.getY() - ptStart.getY()) / (ptStart.getX() - (ptStart.getX()+100)));
337            //convert alpha to radians
338            double alpha1 = Math.PI * angle / 180;
339
340            //theta is the angle of extension from the x axis
341            double theta = psi + alpha1;
342            //dx is the x extension from pt2
343            double dx = distance * Math.cos(theta);
344            //dy is the y extension form pt2
345            double dy = distance * Math.sin(theta);
346            newX = ptStart.getX() + dx;
347            newY = ptStart.getY() + dy;
348
349            pt.setLocation(newX, newY);
350        } catch (Exception exc) {
351            System.out.println(exc.getMessage());
352            exc.printStackTrace();
353        }
354        return pt;
355    }
356
357    /**
358     *
359     * @param latitude1
360     * @param longitude1
361     * @param latitude2
362     * @param longitude2
363     * @param unitOfMeasure meters, kilometers, miles, feet, yards, nautical,
364     * nautical miles.
365     * @return
366     */
367    public static double measureDistance(double latitude1, double longitude1, double latitude2, double longitude2, String unitOfMeasure) {
368        // latitude1,latitude2 = latitude, longitude1,longitude2 = longitude
369        //Radius is 6378.1 (km), 3963.1 (mi), 3443.9 (nm
370
371        double distance = -1,
372                rad;
373
374        String uom = unitOfMeasure.toLowerCase();
375
376        if (uom.equals("meters")) {
377            rad = 6378137;
378        } else if (uom.equals("kilometers")) {
379            rad = 6378.137;
380        } else if (uom.equals("miles")) {
381            rad = 3963.1;
382        } else if (uom.equals("feet")) {
383            rad = 20925524.9;
384        } else if (uom.equals("yards")) {
385            rad = 6975174.98;
386        } else if (uom.equals("nautical")) {
387            rad = 3443.9;
388        } else if (uom.equals("nautical miles")) {
389            rad = 3443.9;
390        } else {
391            return -1.0;
392        }
393
394        latitude1 = latitude1 * (Math.PI / 180);
395        latitude2 = latitude2 * (Math.PI / 180);
396        longitude1 = longitude1 * (Math.PI / 180);
397        longitude2 = longitude2 * (Math.PI / 180);
398        distance = (Math.acos(Math.cos(latitude1) * Math.cos(longitude1) * Math.cos(latitude2) * Math.cos(longitude2) + Math.cos(latitude1) * Math.sin(longitude1) * Math.cos(latitude2) * Math.sin(longitude2) + Math.sin(latitude1) * Math.sin(latitude2)) * rad);
399
400        return distance;
401    }
402}