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