001package armyc2.c5isr.renderer.utilities;
002
003import android.content.Context;
004import android.graphics.RectF;
005
006import java.io.BufferedReader;
007import java.io.IOException;
008import java.io.InputStream;
009import java.io.InputStreamReader;
010import java.util.ArrayList;
011import java.util.HashMap;
012import java.util.List;
013import java.util.Map;
014import java.util.Set;
015
016
017import armyc2.c5isr.renderer.R;
018
019public class SVGLookup {
020    private static SVGLookup _instance = null;
021    private static Boolean _initCalled = false;
022    private static Map<String, SVGInfo> _SVGLookupD = null;
023    private static Map<String, SVGInfo> _SVGLookupE = null;
024    private String TAG = "SVGLookup";
025
026
027    /*
028     * Holds SymbolDefs for all symbols. (basicSymbolID, Description, MinPoint, MaxPoints, etc...) Call
029     * getInstance().
030     *
031     */
032    private SVGLookup() {
033        // init(null);
034        // _initCalled=true;
035    }
036
037    public static synchronized SVGLookup getInstance() {
038        if (_instance == null) {
039            _instance = new SVGLookup();
040        }
041
042        return _instance;
043    }
044
045    public final synchronized void init(Context context)
046    {
047        if (_initCalled == false)
048        {
049            _SVGLookupD = new HashMap<>();
050            _SVGLookupE = new HashMap<>();
051
052            try
053            {
054                InputStream isD = context.getResources().openRawResource(R.raw.svgd);
055                loadData(isD, SymbolID.Version_2525Dch1);
056                isD.close();
057
058                InputStream isE = context.getResources().openRawResource(R.raw.svge);
059                loadData(isE, SymbolID.Version_2525E);
060                isE.close();
061
062                _initCalled = true;
063            }
064            catch(Exception e)
065            {
066                System.out.println(e.getMessage());
067            }
068        }
069
070    }
071
072    private void loadData(InputStream is, int version)
073    {
074        Map<String, SVGInfo> lookup;
075        if(version == SymbolID.Version_2525E)
076            lookup = _SVGLookupE;
077        else
078            lookup = _SVGLookupD;
079
080        String[] temp = null;
081        String id = null;
082        RectF bbox = null;
083        String svg = null;
084        String delimiter = "~";
085
086        try
087        {
088            BufferedReader br = new BufferedReader(new InputStreamReader(is));
089
090            String line = br.readLine();
091
092            while (line != null)
093            {
094                //parse first line
095                temp = line.split(delimiter);
096                id = temp[0];
097                float left, top, width, height;
098                left = Float.parseFloat(temp[1]);
099                top = Float.parseFloat(temp[2]);
100                width = Float.parseFloat(temp[3]);
101                height = Float.parseFloat(temp[4]);
102                bbox = RectUtilities.makeRectF(left, top, width, height);
103
104                    /*if(id.equals("25130100"))
105                        Log.e("action point",id);//*/
106
107                //read 2nd line to get SVG
108                svg = br.readLine();
109
110                lookup.put(id, new SVGInfo(id, bbox, svg));
111
112                //read next line for next loop
113                line = br.readLine();
114            }
115            _initCalled = true;
116        }
117        catch(IOException ioe)
118        {
119            System.out.println(ioe.getMessage());
120        }
121        catch(Exception e)
122        {
123            System.out.println(e.getMessage());
124        }
125    }
126
127    /**
128     *
129     * @param id
130     * @param version
131     * @return
132     */
133    public SVGInfo getSVGLInfo(String id, int version)
134    {
135        if(version >= SymbolID.Version_2525E)
136        {
137            if (_SVGLookupE.containsKey(id))
138                return _SVGLookupE.get(id);
139        }
140        else
141        {
142            if (_SVGLookupD.containsKey(id))
143                return _SVGLookupD.get(id);
144        }
145
146        return null;
147    }
148
149    public SVGInfo getSVGOctagon()
150    {
151        return _SVGLookupD.getOrDefault("octagon", null);
152    }
153
154    public static String getFrameID(String symbolID)
155    {
156        //SIDC positions 3_456_7
157        // String frameID = symbolID.charAt(2) + "_" + symbolID.substring(3, 6) + "_" + symbolID.charAt(6);
158
159        String frameID = null;
160        String ss;
161        int affiliation = SymbolID.getAffiliation(symbolID);
162        int status = SymbolID.getStatus(symbolID);
163        //Some affiliations are always dashed and only have one SVG for status with a value of 0
164        if(affiliation == SymbolID.StandardIdentity_Affiliation_Pending ||
165                affiliation == SymbolID.StandardIdentity_Affiliation_AssumedFriend ||
166                affiliation == SymbolID.StandardIdentity_Affiliation_Suspect_Joker)
167        {
168            // "When the frame is assumed friend, suspect, or pending, the status shall not be displayed."
169            status = 0;
170        }
171        if(status > 1) // Anything above 1 for status means present for the frame
172            status = 0;
173
174        int context = SymbolID.getContext(symbolID);
175        //they didn't make duplicate frame so I have to change the number for
176        //the lookup to work.
177
178        if(SymbolID.getVersion(symbolID) < SymbolID.Version_2525E)//2525Dch1 or less
179        {
180            switch(SymbolID.getSymbolSet(symbolID))
181            {
182                case 01: //Air
183                case 02: //Air Missile
184                case 51: //Air SIGINT
185                    ss = "01";
186                    break;
187                case 05: //Space
188                case 06: //Space Missile
189                case 50: //Space SIGINT
190                    ss = "05";
191                    break;
192                case 10: //Land Unit
193                case 11://Land Civilian Unit/Org
194                    ss = "10";
195                    break;
196                case 15://Land Equipment
197                case 52://Land SigInt
198                case 53://Sea Surface SIGINT
199                    ss = "30";
200                    break;
201                case 30://Sea Surface
202                    ss = "30";
203                    if(SymbolID.getEntityCode(symbolID)==150000)
204                        return "octagon";//this symbol has no frame and a size of 1L x 1L.
205                    break;
206                case 20: //Land Installation
207                    ss = "20";
208                    break;
209                case SymbolID.SymbolSet_DismountedIndividuals: //Dismounted Individuals
210                    ss = "27";
211                    break;
212                case 35: //Sea Subsurface
213                case 36: //Mine Warfare
214                case 54: //Sea Subsurface SigInt
215                    ss = "35";
216                    break;
217                case 40: //Activities/Events
218                    ss = "40";
219                    break;
220                case 60: //Cyberspace
221                    ss = "60"; //No cyberspace SVG frame at the moment so setting to activities
222                    break;
223                default:
224                    ss = "00";
225
226                    if(context == SymbolID.StandardIdentity_Context_Exercise && affiliation > SymbolID.StandardIdentity_Affiliation_Unknown)
227                    {
228                        //really there are no unknown exercise symbols outside of pending and unknown
229                        //default to unknown
230                        affiliation = SymbolID.StandardIdentity_Affiliation_Unknown;
231                    }
232            }
233            frameID = context + "_" + affiliation + ss + "_" + status;
234        }
235        else//2525E or above
236        {
237            char frameShape = SymbolID.getFrameShape(symbolID);
238            if(frameShape==SymbolID.FrameShape_Unknown)
239            {
240
241                /*if(SymbolID.getSymbolSet(symbolID) != SymbolID.SymbolSet_SignalsIntelligence)
242                {//get frame shape associated with symbol set
243                    frameShape=SymbolID.getDefaultFrameShape(symbolID);
244                }//*/
245                frameShape=SymbolID.getDefaultFrameShape(symbolID);
246                if(context == SymbolID.StandardIdentity_Context_Exercise &&
247                        SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_Unknown &&
248                        affiliation > SymbolID.StandardIdentity_Affiliation_Unknown)
249                {
250                    //really there are no unknown exercise symbols outside pending and unknown affiliations
251                    //default to unknown
252                    affiliation = SymbolID.StandardIdentity_Affiliation_Unknown;
253                }
254            }
255            if(SymbolID.getSymbolSet(symbolID)==SymbolID.SymbolSet_SeaSurface &&
256                    SymbolID.getEntityCode(symbolID)==150000 &&  //Own Ship
257                    (frameShape == SymbolID.FrameShape_LandEquipment_SeaSurface || frameShape == SymbolID.FrameShape_Unknown))
258            {
259                return "octagon";
260            }
261            frameID = context + "_" + affiliation + frameShape + "_" + status;
262        }
263        return frameID;
264    }
265
266    public static String getMainIconID(String symbolID)
267    {
268        //SIDC positions 5-6 + 11-16
269        String mainIconID = symbolID.substring(4, 6) + symbolID.substring(10, 16);
270        int ss = SymbolID.getSymbolSet(symbolID);
271
272        if(ss == SymbolID.SymbolSet_MineWarfare)
273        {
274            if(RendererSettings.getInstance().getSeaMineRenderMethod() == RendererSettings.SeaMineRenderMethod_ALT ||
275                    mainIconID.equals("36110600") || mainIconID.equals("36110700"))
276            {
277                mainIconID += "_a";
278            }
279        }
280        else if(ss == SymbolID.SymbolSet_LandUnit)
281        {
282            switch(SymbolID.getEntityCode(symbolID))
283            {
284                case 111000:
285                case 111001:
286                case 111002:
287                case 111003:
288                case 111004:
289                case 111005:
290                case 120100:
291                case 120400:
292                case 120401:
293                case 120402:
294                case 120501:
295                case 120502:
296                case 120601:
297                case 120801:
298                case 121100:
299                case 121101:
300                case 121102:
301                case 121103:
302                case 121104:
303                case 121105:
304                case 121106:
305                case 121300:
306                case 121301:
307                case 121302:
308                case 121303:
309                case 121802:
310                case 130100:
311                case 130101:
312                case 130102:
313                case 130103:
314                case 130200:
315                case 130302:
316                case 140102:
317                case 140103:
318                case 140104:
319                case 140105:
320                case 140702:
321                case 140703:
322                case 141702:
323                case 150504:
324                case 150800:
325                case 160200:
326                case 161200:
327                case 161300:
328                case 161400:
329                case 161700:
330                case 161800:
331                case 161900:
332                case 162000:
333                case 162100:
334                case 162200:
335                case 163400:
336                case 163700:
337                case 163800:
338                case 163900:
339                case 164000:
340                case 164100:
341                case 164200:
342                case 164300:
343                case 164400:
344                case 164500:
345                case 164600:
346                case 165000://NATO Only
347                    //do thing to append correct number
348                    mainIconID += getPostFixForIcon(symbolID);
349                    break;
350                default:
351                    break;
352            }
353
354        }
355        else if(ss == SymbolID.SymbolSet_LandEquipment)
356        {
357            switch (SymbolID.getEntityCode(symbolID))
358            {
359                case 120111:
360                    //do thing to append correct number
361                    mainIconID += getPostFixForIcon(symbolID);
362                    break;
363                default:
364                    break;
365            }
366        }
367        else if(ss == SymbolID.SymbolSet_LandInstallation)
368        {
369            switch (SymbolID.getEntityCode(symbolID))
370            {
371                case 110300:
372                case 111200:
373                case 120103:
374                case 120105:
375                case 120106:
376                case 120107:
377                case 120701:
378                case 120702:
379                    //do thing to append correct number
380                    mainIconID += getPostFixForIcon(symbolID);
381                    break;
382                default:
383                    break;
384            }
385        }
386        else if(ss == SymbolID.SymbolSet_Activities)
387        {
388            switch (SymbolID.getEntityCode(symbolID))
389            {
390                case 110303:
391                case 130201:
392                case 131202:
393                case 131208:
394                    //do thing to append correct number
395                    mainIconID += getPostFixForIcon(symbolID);
396                    break;
397                default:
398                    break;
399            }
400        }
401        else if(ss == SymbolID.SymbolSet_Unknown)
402            mainIconID = "00000000";//unknown with question mark
403        else if (ss != SymbolID.SymbolSet_Air &&
404                ss != SymbolID.SymbolSet_AirMissile &&
405                ss != SymbolID.SymbolSet_Space &&
406                ss != SymbolID.SymbolSet_SpaceMissile &&
407                ss != SymbolID.SymbolSet_LandCivilianUnit_Organization &&
408                ss != SymbolID.SymbolSet_DismountedIndividuals &&
409                ss != SymbolID.SymbolSet_ControlMeasure &&
410                ss != SymbolID.SymbolSet_SeaSurface &&
411                ss != SymbolID.SymbolSet_SeaSubsurface &&
412                ss != SymbolID.SymbolSet_Atmospheric &&
413                ss != SymbolID.SymbolSet_Oceanographic &&
414                ss != SymbolID.SymbolSet_MeteorologicalSpace &&
415                ss != SymbolID.SymbolSet_SignalsIntelligence_Space &&
416                ss != SymbolID.SymbolSet_SignalsIntelligence_Air &&
417                ss != SymbolID.SymbolSet_SignalsIntelligence_Land &&
418                ss != SymbolID.SymbolSet_SignalsIntelligence_SeaSurface &&
419                ss != SymbolID.SymbolSet_SignalsIntelligence_SeaSubsurface &&
420                ss != SymbolID.SymbolSet_CyberSpace)
421        {
422            mainIconID = "98100000";//invalid symbol, inverted question mark
423        }
424
425        return mainIconID;
426    }
427
428
429    private static String getPostFixForIcon(String symbolID)
430    {
431        int aff = SymbolID.getAffiliation(symbolID);
432        String pf = "";
433        if(aff == SymbolID.StandardIdentity_Affiliation_Friend ||
434                aff == SymbolID.StandardIdentity_Affiliation_AssumedFriend)
435            pf += "_1";
436        else if(aff == SymbolID.StandardIdentity_Affiliation_Neutral)
437            pf += "_2";
438        else if(aff == SymbolID.StandardIdentity_Affiliation_Hostile_Faker ||
439                aff == SymbolID.StandardIdentity_Affiliation_Suspect_Joker)
440            pf += "_3";
441        else if(aff == SymbolID.StandardIdentity_Affiliation_Unknown ||
442                aff == SymbolID.StandardIdentity_Affiliation_Pending)
443            pf += "_0";
444
445        return pf;
446    }
447
448    public static String getMod1ID(String symbolID)
449    {
450        String mod1ID = null;
451
452
453        if((SymbolID.getVersion(symbolID)>=SymbolID.Version_2525E) && symbolID.charAt(20) !='0')
454        {//2525E with Modifier 1 Indicator set
455            mod1ID = symbolID.substring(20,21) + symbolID.substring(16, 18) + "_1";
456        }
457        else //2525D or no Modifier 1 Indicator set
458        {
459            //SIDC positions 5-6 + 17-18 + "1"
460
461            if(SymbolID.getEntity(symbolID)>=11)
462                mod1ID = symbolID.substring(4, 6) + symbolID.substring(16, 18) + "1";
463            else
464                mod1ID = symbolID.substring(4, 6) + "001";
465
466            if(SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_LandUnit)
467            {
468                switch(SymbolID.getModifier1(symbolID))
469                {
470                    case 98:
471                        mod1ID += getPostFixForIcon(symbolID);
472                        break;
473                    default:
474                        break;
475                }
476            }
477        }
478        return mod1ID;
479    }
480
481    public static String getMod2ID(String symbolID)
482    {
483        String mod2ID = null;
484        if((SymbolID.getVersion(symbolID)>=SymbolID.Version_2525E) && symbolID.charAt(21) != '0')
485        {//2525E with Modifier 1 Indicator set
486            mod2ID = symbolID.substring(21,22) + symbolID.substring(18, 20) + "_2";
487        }
488        else //2525D or no Modifier 1 Indicator set
489        {
490            //SIDC positions 5-6 + 19-20 + "2"
491            if(SymbolID.getEntity(symbolID)>=11)
492                mod2ID = symbolID.substring(4, 6) + symbolID.substring(18, 20) + "2";
493            else
494                mod2ID = symbolID.substring(4, 6) + "002";
495
496            if(SymbolID.getSymbolSet(symbolID) == SymbolID.SymbolSet_LandUnit)
497            {
498                switch(SymbolID.getModifier2(symbolID))
499                {
500                    case 60:
501                    case 62:
502                    case 84:
503                    case 89:
504                        mod2ID += getPostFixForIcon(symbolID);
505                        break;
506                    default:
507                        break;
508                }
509            }
510        }
511        return mod2ID;
512    }
513
514    public static String getEchelonAmplifier(String symbolID)
515    {
516        String amp = null;
517        int ver = SymbolID.getVersion(symbolID);
518        if (ver < SymbolID.Version_2525E)
519        {
520            amp = symbolID.charAt(3) + symbolID.substring(8,10);
521        }
522        else // >= 2525E
523        {
524            //This will eventually be different with the introduction of the frame shape modifier
525            amp = symbolID.charAt(3) + symbolID.substring(8,10);
526        }
527        return amp;
528    }
529
530    public static String getHQTFFD(String symbolID) {
531        String hqtffd = null;
532        int ver = SymbolID.getVersion(symbolID);
533        if (ver < SymbolID.Version_2525E)
534        {
535            hqtffd = symbolID.substring(3, 6) + symbolID.charAt(7);
536        }
537        else // >= 2525E
538        {
539            //This will eventually be different with the introduction of the frame shape modifier
540            hqtffd = symbolID.substring(3, 6) + symbolID.charAt(7);
541        }
542        return hqtffd;
543    }
544
545    public static String getOCA(String symbolID, boolean useSlash)
546    {
547        if(useSlash)
548        {
549            int status = SymbolID.getStatus(symbolID);
550            if(status == SymbolID.Status_Present_Damaged || status == SymbolID.Status_Present_Destroyed)
551                return String.valueOf(status);
552            else
553                return null;
554        }
555        else//get the bar
556        {
557            String oca = null;
558            int ver = SymbolID.getVersion(symbolID);
559            if(ver < SymbolID.Version_2525E)
560            {
561                oca = symbolID.substring(2,7) + "2";
562            }
563            else // >= 2525E
564            {
565                //This will eventually be different with the introduction of the frame shape modifier
566                oca = symbolID.substring(2,7) + "2";
567            }
568            return oca;
569        }
570    }
571    public static List<String> getAllKeys()
572    {
573        List<String> kl = new ArrayList();
574        Set<String> keys = _SVGLookupD.keySet();
575        for(String key: keys) {
576            //System.out.println(key);
577            kl.add(key);
578        }
579        return kl;
580    }
581
582    /**
583     *
584     * @param node
585     * <a href="https://stackoverflow.com/questions/4412848/xml-node-to-string-in-java">
586     *     https://stackoverflow.com/questions/4412848/xml-node-to-string-in-java</a>
587     */
588    /*private static String nodeToString(Node node)
589    {
590        StringWriter sw = new StringWriter();
591        try
592        {
593            Transformer t = TransformerFactory.newInstance().newTransformer();
594            t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
595            t.setOutputProperty(OutputKeys.INDENT, "yes");
596            t.transform(new DOMSource(node), new StreamResult(sw));
597        }
598        catch(TransformerException te)
599        {
600            System.out.println(te.getMessage());
601        }
602        return sw.toString();
603    }//*/
604
605    /*
606     * For use only by MilStdIconRenderer.addCustomSymbol()
607     * @param svgInfo with the basic symbol id, bounds of the SVG, SVG group
608     * @param version like SymbolID.Version_2525E
609     * @return
610     */
611    public boolean addCustomSymbol(SVGInfo svgInfo, int version)
612    {
613        boolean success = false;
614        try
615        {
616            String basicID = svgInfo.getID();
617            if (version < SymbolID.Version_2525E)
618            {
619                if(SVGLookup._SVGLookupD.containsKey(svgInfo.getID()) == false)
620                {
621                    SVGLookup._SVGLookupD.put(svgInfo.getID(),svgInfo);
622                }
623            }
624            else if (version == SymbolID.Version_2525E)
625            {
626                if(SVGLookup._SVGLookupE.containsKey(svgInfo.getID()) == false)
627                {
628                    SVGLookup._SVGLookupE.put(svgInfo.getID(),svgInfo);
629                }
630            }
631        }
632        catch(Exception e)
633        {
634            ErrorLogger.LogException("SVGLookup","addCUstomSymbol",e);
635        }
636        return success;
637    }
638}
639
640