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