001package armyc2.c5isr.renderer;
002
003import android.content.Context;
004import android.util.DisplayMetrics;
005import android.util.Log;
006import android.view.WindowManager;
007
008import java.util.HashMap;
009import java.util.Map;
010import java.util.concurrent.atomic.AtomicBoolean;
011import java.util.logging.Level;
012
013import armyc2.c5isr.renderer.utilities.DrawRules;
014import armyc2.c5isr.renderer.utilities.ErrorLogger;
015import armyc2.c5isr.renderer.utilities.GENCLookup;
016import armyc2.c5isr.renderer.utilities.ImageInfo;
017import armyc2.c5isr.renderer.utilities.MSInfo;
018import armyc2.c5isr.renderer.utilities.MSLookup;
019import armyc2.c5isr.renderer.utilities.MilStdAttributes;
020import armyc2.c5isr.renderer.utilities.RendererSettings;
021import armyc2.c5isr.renderer.utilities.SVGInfo;
022import armyc2.c5isr.renderer.utilities.SVGLookup;
023import armyc2.c5isr.renderer.utilities.SVGSymbolInfo;
024import armyc2.c5isr.renderer.utilities.SymbolID;
025import armyc2.c5isr.renderer.utilities.SymbolUtilities;
026
027/**
028 * This class is used for rendering icons that represent the single point graphics in the MilStd 2525.
029 * It can also be used for rendering icon previews for multipoint graphics.
030 */
031public class MilStdIconRenderer
032/* implements IIconRenderer */ {
033
034    private String TAG = "MilStdIconRenderer";
035
036    private static MilStdIconRenderer _instance = null;
037    private AtomicBoolean _initSuccess = new AtomicBoolean(false);
038    private SinglePointRenderer _SPR = null;
039
040    private SinglePointSVGRenderer _SPSVGR = null;
041        public static synchronized MilStdIconRenderer getInstance()
042    {
043        if (_instance == null) {
044            _instance = new MilStdIconRenderer();
045        }
046        return _instance;
047    }
048
049    /**
050     *
051     * @param context
052     */
053    public synchronized void init(Context context)// List<Typeface> fonts, List<String> xml
054    {
055        try {
056            if (!_initSuccess.get()) {
057
058                //test SVGLookup////////////////////////////////////////////////////////////////////
059                SVGLookup.getInstance().init(context);
060                /*SVGInfo oct = SVGLookup.getInstance().getSVGLInfo("octagon");
061                System.out.println(oct.toString());//*/
062
063                //test MSLookup/////////////////////////////////////////////////////////////////////
064                MSLookup.getInstance().init(context);
065
066                /*MSInfo msi = MSLookup.getInstance().getMSLInfo("50110100",0);//
067                msi = MSLookup.getInstance().getMSLInfo("36190100",0);//"Non-Mine Mine–Like Object, Bottom"
068                System.out.println(msi.getPath());
069                System.out.println(msi.getName());
070                msi = MSLookup.getInstance().getMSLInfo("01110300",0);//"Unmanned Aircraft (UA) / Unmanned Aerial Vehicle (UAV) / Unmanned Aircraft System (UAS) / Remotely Piloted Vehicle (RPV)"
071                System.out.println(msi.getPath());
072                System.out.println(msi.getName());//*/
073
074                DisplayMetrics dm = new DisplayMetrics();
075                context.getSystemService(WindowManager.class).getDefaultDisplay().getRealMetrics(dm);
076                RendererSettings.getInstance().setDeviceDPI(dm.densityDpi);
077                RendererSettings.getInstance().setDeviceHeight(dm.heightPixels);
078                RendererSettings.getInstance().setDeviceWidth(dm.widthPixels);
079
080                //Country Codes
081                GENCLookup.getInstance().init(context);
082
083                // setup single point renderer
084                _SPR = SinglePointRenderer.getInstance();
085                _SPSVGR = SinglePointSVGRenderer.getInstance();
086
087                _initSuccess.set(true);
088            }
089
090        } catch (Exception exc) {
091            Log.e(TAG, exc.getMessage(), exc);
092        }
093    }
094
095    public synchronized boolean isReady()
096    {
097        return _initSuccess.get();
098    }
099
100    // @Override
101
102    /**
103     * Checks symbol codes and returns whether they can be rendered.
104     * For multi-point graphics, modifiers are ignored because we don't need that
105     * information to show preview icons in the SymbolPicker.
106     *
107     * @param symbolID 20-30 digit 2525D Symbol ID Code
108     * @param attributes (currently unused)
109     * @return true if the basic form of the graphic can be rendered
110     */
111    public Boolean CanRender(String symbolID, Map<String,String> attributes)
112    {
113        String message = "";
114        try {
115            // Extract 8-digit ID to use with SVGLookup.
116            // MSLookup can handle long codes, but SVGLookup can't because it also takes other strings.
117            String lookupID = SymbolUtilities.getBasicSymbolID(symbolID);
118            String lookupSVGID = SVGLookup.getMainIconID(symbolID);
119
120            // Renderer only supports 2525D at the moment. 2525E will be in the future.
121            /*
122            int symStd = -1;
123            int version = SymbolID.getVersion(symbolID);
124            //SymbolID.Version_2525Dch1
125            //SymbolID.Version_2525E
126            */
127
128            MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID);
129            if (msi == null) {
130                message = String.format("Cannot find %s in MSLookup", lookupID);
131            } else if (msi.getDrawRule() == DrawRules.DONOTDRAW) {
132                message = String.format("%s (%s) is DoNotDraw", lookupID, msi.getName());
133            } else
134            {
135                int version = SymbolID.getVersion(symbolID);
136                SVGInfo si = SVGLookup.getInstance().getSVGLInfo(lookupSVGID,version);
137                if (si != null)// || (SymbolID.getEntityCode(symbolID)==000000 && SVGLookup.getInstance().getSVGLInfo(SVGLookup.getFrameID(symbolID)) != null))
138                {
139                    return true;
140                }
141                else
142                {
143                    message = String.format("Cannot find %s (%s) in SVGLookup", lookupID, msi.getName());
144                }
145            }
146        } catch (Exception exc) {
147            ErrorLogger.LogException("MilStdIconRenderer", "CanRender", exc);
148        }
149        // ErrorLogger.LogMessage(this.getClass().getName(), "CanRender()", message, Level.FINE);
150        Log.d("MilStdIconRenderer.CanRender()", message);
151        return false;
152    }
153
154
155
156    // @Override
157    public ImageInfo RenderIcon(String symbolID, Map<String,String> modifiers,
158            Map<String,String> attributes)
159    {
160
161
162        int ss = SymbolID.getSymbolSet(symbolID);
163
164        ImageInfo temp = null;
165        MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID);
166        if (msi == null)
167        {
168            //TODO: if null, try to fix the code so that something renders
169                /*symbolID = SymbolUtilities.reconcileSymbolID(symbolID);
170                basicSymbolID = SymbolUtilities.getBasicSymbolIDStrict(symbolID);
171                sd = SymbolDefTable.getInstance().getSymbolDef(basicSymbolID, symStd);//*/
172        }
173        if (msi != null && msi.getDrawRule() == DrawRules.DONOTDRAW) {
174            return null;
175        }
176
177        if (ss==SymbolID.SymbolSet_ControlMeasure)
178        {
179            if (msi != null) {
180                //Point12 is actually a multipoint and 17 & 18 are rectangular target and sector range fan
181                if (SymbolUtilities.isMultiPoint(symbolID)==false) {
182                    temp = _SPR.RenderSP(symbolID, modifiers, attributes);
183                } else {
184                    temp = _SPR.RenderSP(symbolID, null, attributes);
185                }
186            }
187        }
188        else if(ss==SymbolID.SymbolSet_Atmospheric ||
189                ss==SymbolID.SymbolSet_Oceanographic ||
190                ss==SymbolID.SymbolSet_MeteorologicalSpace)
191        {
192            temp = _SPR.RenderSP(symbolID, modifiers, attributes);
193        }
194        else
195        {
196            temp = _SPR.RenderUnit(symbolID, modifiers, attributes);
197        }
198
199        return temp;
200    }
201
202    public SVGSymbolInfo RenderSVG(String symbolID, Map<String,String> modifiers,
203                                   Map<String,String> attributes)
204    {
205
206        //Update to use _SPSVGR.RenderUnit
207        int ss = SymbolID.getSymbolSet(symbolID);
208
209        ImageInfo temp = null;
210        SVGSymbolInfo svgTemp = null;
211        MSInfo msi = MSLookup.getInstance().getMSLInfo(symbolID);
212        if (msi == null)
213        {
214            //TODO: if null, try to fix the code so that something renders
215                /*symbolID = SymbolUtilities.reconcileSymbolID(symbolID);
216                basicSymbolID = SymbolUtilities.getBasicSymbolIDStrict(symbolID);
217                sd = SymbolDefTable.getInstance().getSymbolDef(basicSymbolID, symStd);//*/
218        }
219        if (msi != null && msi.getDrawRule() == DrawRules.DONOTDRAW)
220        {
221            return null;
222        }
223
224        if (ss==SymbolID.SymbolSet_ControlMeasure)
225        {
226            if (msi != null) {
227                //Point12 is actually a multipoint and 17 & 18 are rectangular target and sector range fan
228                if (SymbolUtilities.isMultiPoint(symbolID)==false) {
229                    svgTemp = _SPSVGR.RenderSP(symbolID, modifiers, attributes);
230                } else {
231                    svgTemp = _SPSVGR.RenderSP(symbolID, null, attributes);
232                }
233            }
234        }
235        else if(ss==SymbolID.SymbolSet_Atmospheric ||
236                ss==SymbolID.SymbolSet_Oceanographic ||
237                ss==SymbolID.SymbolSet_MeteorologicalSpace)
238        {
239            svgTemp = _SPSVGR.RenderSP(symbolID, modifiers, attributes);
240        }
241        else
242        {
243            svgTemp = _SPSVGR.RenderUnit(symbolID, modifiers, attributes);
244        }
245
246        return svgTemp;
247    }
248
249    // @Override
250    public String getRendererID()
251    {
252
253        return "milstd2525";
254    }
255
256    private Map<String,String> getDefaultAttributes(String symbolID)
257    {
258        Map<String,String> map = new HashMap<>();
259        try {
260            if (symbolID == null || symbolID.length() != 15) {
261                if (symbolID == null) {
262                    symbolID = "null";
263                }
264                ErrorLogger.LogMessage("MilStdIconRenderer", "getDefaultAttributes",
265                        "getDefaultAttributes passed bad symbolID: " + symbolID);
266                return null;
267            }
268
269            map.put(MilStdAttributes.Alpha, "1.0");
270            if (SymbolUtilities.hasDefaultFill(symbolID)) {
271                map.put(MilStdAttributes.FillColor,
272                        SymbolUtilities.getFillColorOfAffiliation(symbolID).toHexString());
273            }
274
275            map.put(MilStdAttributes.LineColor,
276                    SymbolUtilities.getLineColorOfAffiliation(symbolID).toHexString());
277
278            map.put(MilStdAttributes.OutlineSymbol, "false");
279            // attribute[MilStdAttributes.SymbolOutlineColor] = null;
280            // map.put(MilStdAttributes.OutlineWidth,"1");
281
282            map.put(MilStdAttributes.DrawAsIcon, "false");
283
284            RendererSettings rs = RendererSettings.getInstance();
285
286            map.put(MilStdAttributes.KeepUnitRatio, "true");
287            return map;
288        } catch (Exception exc) {
289            ErrorLogger.LogException("MilStdIconRenderer", "getDefaultAttributes", exc);
290        }
291        return map;
292    }
293
294    /**
295     * Add a custom framed symbol to the renderer's collection
296     * @param msInfo
297     * @param svgInfo
298     * @return
299     */
300    public boolean AddCustomSymbol(MSInfo msInfo, SVGInfo svgInfo)
301    {
302        boolean success = false;
303        if(msInfo.getBasicSymbolID().equals(svgInfo.getID()))//Make sure IDs match
304        {
305            //Make sure entry isn't already there
306            if(MSLookup.getInstance().getMSLInfo(msInfo.getBasicSymbolID(),msInfo.getVersion())==null &&
307                    SVGLookup.getInstance().getSVGLInfo(svgInfo.getID(),msInfo.getVersion())==null)
308            {
309                if(MSLookup.getInstance().addCustomSymbol(msInfo))
310                    success = SVGLookup.getInstance().addCustomSymbol(svgInfo,msInfo.getVersion());
311            }
312        }
313        else
314        {
315            ErrorLogger.LogMessage("Symbol Set and Entity Codes do not match", Level.INFO,false);
316        }
317        return success;
318    }
319}