class OpenLRXMLDecoder implements PhysicalDecoder {

    @Override
    public final RawLocationReference decodeData(final LocationReference lr)
            throws PhysicalFormatException {
        Object data = lr.getLocationReferenceData();
        if (!(data instanceof OpenLR)) {
            throw new OpenLRXMLException(XMLErrorType.DATA_ERROR,
                    "incorrect data class");
        }
        OpenLR xmlData = (OpenLR) data;
        String id = xmlData.getLocationID();
        XMLLocationReference xmlLoc = xmlData.getXMLLocationReference();
        if (xmlLoc == null) {
            throw new OpenLRXMLException(XMLErrorType.BINARY_DATA_ONLY,
                    "cannot decode binary string using xml package");
        }

        LineLocationReference lineLoc = xmlLoc.getLineLocationReference();
        PointLocationReference pointLoc = xmlLoc.getPointLocationReference();
        /** DLR e.V. (LTouk) XML area location reference */
        AreaLocationReference areaLoc = xmlLoc.getAreaLocationReference();

        if (lineLoc == null && pointLoc == null && areaLoc == null) {
            throw new OpenLRXMLException(XMLErrorType.DATA_ERROR,
                    "no location reference");
        }

        RawLocationReference rawLocRef = null;
        if (lineLoc != null) {
            LineDecoder decoder = new LineDecoder();
            rawLocRef = decoder.decodeData(id, lineLoc);
        } else if (pointLoc != null) {
            GeoCoordinate gCoord = pointLoc.getGeoCoordinate();
            PointAlongLine pal = pointLoc.getPointAlongLine();
            PoiWithAccessPoint palwap = pointLoc.getPoiWithAccessPoint();
            if (gCoord == null && pal == null && palwap == null) {
                throw new OpenLRXMLException(XMLErrorType.DATA_ERROR,
                        "no point location found");
            }
            if (gCoord != null) {
                GeoCoordDecoder decoder = new GeoCoordDecoder();
                rawLocRef = decoder.decodeData(id, gCoord);
            } else if (pal != null) {
                PointAlongDecoder decoder = new PointAlongDecoder();
                rawLocRef = decoder.decodeData(id, pal);
            } else if (palwap != null) {
                PoiAccessDecoder decoder = new PoiAccessDecoder();
                rawLocRef = decoder.decodeData(id, palwap);
            }
        } else if (areaLoc != null) {
            /** DLR e.V. (LTouk) XML circle location reference */
            CircleLocationReference circleLoc = areaLoc
                    .getCircleLocationReference();
            RectangleLocationReference rectangleLoc = areaLoc
                    .getRectangleLocationReference();
            GridLocationReference gridLoc = areaLoc.getGridLocationReference();
            PolygonLocationReference polygonLoc = areaLoc
                    .getPolygonLocationReference();
            ClosedLineLocationReference closedLineLoc = areaLoc
                    .getClosedLineLocationReference();

            if (circleLoc == null && polygonLoc == null && rectangleLoc == null
                    && gridLoc == null && closedLineLoc == null) {
                throw new OpenLRXMLException(XMLErrorType.DATA_ERROR,
                        "no area location found");
            }
            if (circleLoc != null) {
                CircleDecoder circleDecoder = new CircleDecoder();
                rawLocRef = circleDecoder.decodeData(id, circleLoc);
            } else if (rectangleLoc != null) {
                RectangleDecoder rectangleDecoder = new RectangleDecoder();
                rawLocRef = rectangleDecoder.decodeData(id, rectangleLoc);
            } else if (gridLoc != null) {
                GridDecoder gridDecoder = new GridDecoder();
                rawLocRef = gridDecoder.decodeData(id, gridLoc);
            } else if (polygonLoc != null) {
                PolygonDecoder polygonDecoder = new PolygonDecoder();
                rawLocRef = polygonDecoder.decodeData(id, polygonLoc);
            } else if (closedLineLoc != null) {
                ClosedLineDecoder closedLineDecoder = new ClosedLineDecoder();
                rawLocRef = closedLineDecoder.decodeData(id, closedLineLoc);
            }

        }

        return rawLocRef;
    }

}