<html>
<head>
  <script src="../OLLoader.js"></script>
  <script type="text/javascript">

    function test_initialize(t) {
        t.plan(2);

        var protocol = new OpenLayers.Protocol.WFS({
            url: "http://some.url.org",
            featureNS: "http://namespace.org",
            featureType: "type"
        });
        t.ok(protocol instanceof OpenLayers.Protocol.WFS.v1_0_0,
             "initialize returns instance of default versioned protocol")

        var protocol = new OpenLayers.Protocol.WFS({
            url: "http://some.url.org",
            featureNS: "http://namespace.org",
            featureType: "type",
            version: "1.1.0"
        });
        t.ok(protocol instanceof OpenLayers.Protocol.WFS.v1_1_0,
             "initialize returns instance of custom versioned protocol")
    }

    function test_setGeometryName(t) {
        t.plan(4);
        var protocol = new OpenLayers.Protocol.WFS({
            url: "http://some.url.org",
            featureNS: "http://namespace.org",
            featureType: "type",
            geometryName: "geom"
        });
        t.eq(protocol.geometryName, "geom", "geometryName set correctly by constructor");
        t.eq(protocol.format.geometryName, "geom", "geometryName correctly set on format by constructor");
        // change the geometryName on the fly
        protocol.setGeometryName("SHAPE");
        t.eq(protocol.geometryName, "SHAPE", "geometryName changed correctly by setGeometryName");
        t.eq(protocol.format.geometryName, "SHAPE", "geometryName correctly changed on format by setGeometryName");
        protocol.destroy();
    }

    function test_setFeatureType(t) {
        t.plan(4);
        var protocol = new OpenLayers.Protocol.WFS({
            url: "http://some.url.org",
            featureNS: "http://namespace.org",
            featureType: "type"
        });
        t.eq(protocol.featureType, "type", "featureType set correctly by constructor");
        t.eq(protocol.format.featureType, "type", "featureType correctly set on format by constructor");
        // change the feature type on the fly
        protocol.setFeatureType("foo");
        t.eq(protocol.featureType, "foo", "featureType changed correctly by setFeatureType");
        t.eq(protocol.format.featureType, "foo", "featureType correctly changed on format by setFeatureType");
        protocol.destroy();
    }

    function test_read(t) {
        t.plan(7);

        var protocol = new OpenLayers.Protocol.WFS({
            url: "http://some.url.org",
            featureNS: "http://namespace.org",
            featureType: "type",
            parseResponse: function(request, options) {
                t.eq(request.responseText, "foo", "parseResponse called properly");
                t.eq(options, {foo: "bar"}, "parseResponse receives readOptions");
                return "foo";
            }
        });

        var _POST = OpenLayers.Request.POST;

        var expected, status;
        OpenLayers.Request.POST = function(obj) {
            t.xml_eq(new OpenLayers.Format.XML().read(obj.data).documentElement, expected, "GetFeature request is correct");
            obj.status = status;
            obj.responseText = "foo";
            t.delay_call(0.1, function() {obj.callback.call(this)});
            return obj;
        };

        expected = readXML("GetFeature_1");
        status = 200;
        var response = protocol.read({readOptions: {foo: "bar"}, callback: function(response) {
            t.eq(response.features, "foo", "user callback properly called with features");
            t.eq(response.code, OpenLayers.Protocol.Response.SUCCESS, "success reported properly");
        }});

        options = {
            maxFeatures: 10,
            featureType: 'type2',
            srsName: 'EPSG:900913',
            featureNS: 'htttp://alternative.namespace.org',
            callback: function(response) {
                t.eq(response.code, OpenLayers.Protocol.Response.FAILURE, "failure reported properly to user callback");
            }
        };
        expected = readXML("GetFeature_2");
        status = 400;
        var response = protocol.read(options);

        OpenLayers.Request.POST = _POST;
    }
    
    function test_parseResponse_poorconfig(t) {
        t.plan(2);

        var protocol = new OpenLayers.Protocol.WFS({
            url: "http://some.url.org",
            featurePrefix: "topp",
            featureType: "tasmania_roads",
            geometryName: null
        });

        protocol.parseResponse({responseText: document.getElementById("query_response").firstChild.nodeValue});
        t.eq(protocol.geometryName, "geom", "geometryName configured correctly");
        t.eq(protocol.featureNS, "http://www.openplans.org/topp", "featureNS configured correctly");
    }

    function test_exception(t) {
        t.plan(8);
        var url = "http://some.url.org";
        var protocol = new OpenLayers.Protocol.WFS({
            url: url,
            version: "1.1.0",
            featureNS: "http://namespace.org",
            featureType: "type"
        });
        // mock up a response
        var response = {
            priv: {
                status: 200,
                responseText: '<?xml version="1.0" encoding="UTF-8"?><ows:ExceptionReport language="en" version="1.0.0" xsi:schemaLocation="http://www.opengis.net/ows http://schemas.opengis.net/ows/1.0.0/owsExceptionReport.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ows="http://www.opengis.net/ows"><ows:Exception locator="foo" exceptionCode="InvalidParameterValue"><ows:ExceptionText>Update error: Error occurred updating features</ows:ExceptionText><ows:ExceptionText>Second exception line</ows:ExceptionText></ows:Exception></ows:ExceptionReport>'
            }
        };
        var log, entry, expected;
        
        // test GetFeature
        log = [];
        protocol.handleRead(OpenLayers.Util.extend({}, response), {
            callback: function(resp) {
                log.push(resp);
            }
        });
        expected = {
            exceptionReport: {
                version: "1.0.0",
                language: "en",
                exceptions: [{
                    code: "InvalidParameterValue",
                    locator: "foo",
                    texts: [
                        "Update error: Error occurred updating features",
                        "Second exception line"
                    ]
                }]
            },
            success: false
        };

        t.eq(log.length, 1, "GetFeature handled");
        entry = log[0];
        t.eq(entry.code, OpenLayers.Protocol.Response.FAILURE, "GetFeature failure reported");
        t.ok(!!entry.error, "GetFeature got error");
        t.eq(entry.error, expected, "GetFeature error matches expected");

        // test a commit
        log = [];
        protocol.handleCommit(response, {
            callback: function(resp) {
                log.push(resp);
            }
        });
        t.eq(log.length, 1, "commit handled");
        entry = log[0];
        t.eq(entry.code, OpenLayers.Protocol.Response.FAILURE, "commit failure reported");
        t.ok(!!entry.error, "commit got error");
        t.eq(entry.error, expected, "GetFeature error matches expected");

    }

    function test_commit(t){
        t.plan(5);

        var url = "http://some.url.org";
        var protocol = new OpenLayers.Protocol.WFS({
            url: url,
            featureNS: "http://namespace.org",
            featureType: "type"
        });
        protocol.format.read = function(data) {
            t.eq(data, "foo", "callback called with correct argument");
            return {
                insertIds: new Array(3),
                success: true
            }
        };

        var _POST = OpenLayers.Request.POST;

        var expected;
        OpenLayers.Request.POST = function(obj) {
            t.xml_eq(new OpenLayers.Format.XML().read(obj.data).documentElement, expected, "Transaction XML with Insert, Update and Delete created correctly");
            t.eq(obj.headers, {foo: 'bar'}, "HTTP headers passed from commit to Request.POST");
            obj.responseText = "foo";
            t.delay_call(0.1, function() {obj.callback.call(this)});
            return obj;
        };

        var featureDelete = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(42, 7), {has : "cheeseburger"});
        featureDelete.fid = "fid.37";
        featureDelete.state = OpenLayers.State.DELETE;
        featureDelete.layer = {
            projection: {
                getCode : function(){
                    return "EPSG:4326";
                }
            }
        }
        var featureInsert = featureDelete.clone();
        featureInsert.state = OpenLayers.State.INSERT;
        var featureModify = featureDelete.clone();
        featureModify.fid = "fid.37";
        featureModify.state = OpenLayers.State.UPDATE;

        options = {
            featureNS: "http://some.namespace.org",
            featureType: "type",
            headers: {foo: 'bar'},
            callback: function(response) {
                t.eq(response.insertIds.length, 3, "correct response passed to user callback");
                t.eq(response.code, OpenLayers.Protocol.Response.SUCCESS, "success properly reported to user callback");
            }
        }

        expected = readXML("commit");
        var response = protocol.commit([featureInsert, featureModify, featureDelete], options);

        OpenLayers.Request.POST = _POST;

    }

    function test_filterDelete(t) {
        t.plan(2)

        var url = "http://some.url.org";
        var protocol = new OpenLayers.Protocol.WFS({
            url: url,
            featureNS: "http://namespace.org",
            featureType: "type"
        });

        var filter = new OpenLayers.Filter.Spatial({
            type: OpenLayers.Filter.Spatial.BBOX,
            value: new OpenLayers.Bounds(-5, -5, 5, 5)
        });

        var _POST = OpenLayers.Request.POST;

        var expected = readXML("filter_delete");
        OpenLayers.Request.POST = function(obj) {
            t.xml_eq(new OpenLayers.Format.XML().read(obj.data).documentElement, expected, "request data correct");
            t.delay_call(0.1, function() {obj.callback.call(this)});
            return obj;
        };

        var response = protocol.filterDelete(filter, {
            callback: function() {
                t.ok("user callback function called");
            }
        });

        OpenLayers.Request.POST = _POST;
    }

    function test_abort(t) {
        t.plan(1);
        var protocol = new OpenLayers.Protocol.WFS({
            url: "http://example.com",
            featureNS: "http://example.com#namespace",
            featureType: "type"
        });

        var response = {
            priv: {
                abort: function() {
                    aborted = true;
                }
            }
        };

        // call abort with mocked response
        var aborted = false;
        protocol.abort(response);
        t.eq(aborted, true, "abort called on response.priv");

    }

    function test_fromWMSLayer(t) {
        t.plan(9);
        var map = new OpenLayers.Map("map", {
            projection: "CRS:84"
        });
        var layer = new OpenLayers.Layer.WMS("foo", "htttp://foo/ows",
            {layers: "topp:states"}
        );
        map.addLayer(layer);
        var protocol = OpenLayers.Protocol.WFS.fromWMSLayer(layer);
        t.eq(protocol.url, "htttp://foo/ows", "url taken from wms layer");
        t.eq(protocol.featurePrefix, "topp", "feature prefix correctly extracted");
        t.eq(protocol.featureType, "states", "typeName correctly extracted");
        t.eq(protocol.srsName, "CRS:84", "srsName set correctly");
        t.eq(protocol.version, "1.1.0", "version set correctly");
        t.eq(protocol.format.geometryName, null, "format's geometryName set to null");

        layer.params["LAYERS"] = ["topp:street_centerline", "topp:states"];
        layer.projection = new OpenLayers.Projection("EPSG:900913");
        protocol = OpenLayers.Protocol.WFS.fromWMSLayer(layer);
        t.eq(protocol.featurePrefix, "topp", "featurePrefix from layer param array");
        t.eq(protocol.featureType, "street_centerline", "first layer from layer param array as featureType");
        t.eq(protocol.srsName, "EPSG:900913", "projection from layer preferred");
    }

    function test_readFormat(t) {
        t.plan(1);

        var protocol = new OpenLayers.Protocol.WFS({
            url: "http://some.url.org",
            featureNS: "http://namespace.org",
            featureType: "type",
            formatOptions: {outputFormat: 'json'},
            readFormat: new OpenLayers.Format.GeoJSON()
        });

        var request = {};
        request.responseText = '{"type":"FeatureCollection","features":[{"type":"Feature","id":"V_HECTOPUNTEN.108411","geometry":{"type":"MultiPoint","coordinates":[[190659.467,349576.19]]},"geometry_name":"ORA_GEOMETRY","properties":{"WEGNUMMER":"002","HECTOMTRNG_ORG":2200,"HECTOMTRNG":"220.00","bbox":[190659.467,349576.19,190659.467,349576.19]}}]}';
        var features = protocol.parseResponse(request);
        t.eq(features.length, 1, "the right format is used to read the request (GeoJSON)");
 	}

    function test_outputFormat(t) {
        t.plan(2);

        var protocol = new OpenLayers.Protocol.WFS({
            version: "1.1.0",
            url: "http://some.url.org",
            featureNS: "http://namespace.org",
            featureType: "type",
            outputFormat: 'json'
        });

        t.ok(protocol.readFormat instanceof OpenLayers.Format.GeoJSON, "the correct readFormat is used for outputFormat JSON");

        protocol = new OpenLayers.Protocol.WFS({
            version: "1.1.0",
            url: "http://some.url.org",
            featureNS: "http://namespace.org",
            featureType: "type",
            outputFormat: 'GML2'
        });

        t.ok(protocol.readFormat instanceof OpenLayers.Format.GML.v2, "the correct readFormat is used for outputFormat GML2");
 	}

    function test_readOptions(t) {
        t.plan(1);

        var protocol = new OpenLayers.Protocol.WFS({
            url: "http://some.url.org",
            version: "1.1.0",
            featureNS: "http://namespace.org",
            featureType: "type",
            readOptions: {'output': 'object'},
            parseResponse: function(request, options) {
                t.eq(options.output, "object", "Options object correctly set to pass on to Format's read");
            }
        });

        var _POST = OpenLayers.Request.POST;

        OpenLayers.Request.POST = function(obj) {
            obj.status = 200;
            obj.responseText = "foo";
            t.delay_call(0.1, function() {obj.callback.call(this)});
            return obj;
        };

        protocol.read({
            callback: function() {}
        });

        OpenLayers.Request.POST = _POST;
    }

    function readXML(id) {
        var xml = document.getElementById(id).firstChild.nodeValue;
        return new OpenLayers.Format.XML().read(xml).documentElement;
    }

  </script>
</head>
<body>
<div id="map" style="width:512px; height:256px"> </div>
<div id="GetFeature_1"><!--
<wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs" service="WFS" version="1.0.0" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <wfs:Query typeName="feature:type" xmlns:feature="http://namespace.org"/>
</wfs:GetFeature>
--></div>
<div id="GetFeature_2"><!--
<wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs" service="WFS" version="1.0.0" maxFeatures="10" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <wfs:Query typeName="feature:type2" xmlns:feature="htttp://alternative.namespace.org"/>
</wfs:GetFeature>
--></div>
<div id="commit"><!--
<wfs:Transaction xmlns:wfs="http://www.opengis.net/wfs" service="WFS" version="1.0.0" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <wfs:Insert>
        <feature:type xmlns:feature="http://namespace.org">
            <feature:the_geom>
                <gml:Point xmlns:gml="http://www.opengis.net/gml" srsName="EPSG:4326">
                    <gml:coordinates decimal="." cs="," ts=" ">42,7</gml:coordinates>
                </gml:Point>
            </feature:the_geom>
            <feature:has>cheeseburger</feature:has>
        </feature:type>
    </wfs:Insert>
    <wfs:Update typeName="feature:type" xmlns:feature="http://namespace.org">
        <wfs:Property>
            <wfs:Name>the_geom</wfs:Name>
            <wfs:Value>
                <gml:Point xmlns:gml="http://www.opengis.net/gml" srsName="EPSG:4326">
                    <gml:coordinates decimal="." cs="," ts=" ">42,7</gml:coordinates>
                </gml:Point>
            </wfs:Value>
        </wfs:Property>
        <wfs:Property>
            <wfs:Name>has</wfs:Name>
            <wfs:Value>cheeseburger</wfs:Value>
        </wfs:Property>
        <ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
            <ogc:FeatureId fid="fid.37"/>
        </ogc:Filter>
    </wfs:Update>
    <wfs:Delete typeName="feature:type" xmlns:feature="http://namespace.org">
        <ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
            <ogc:FeatureId fid="fid.37"/>
        </ogc:Filter>
    </wfs:Delete>
</wfs:Transaction>
--></div>
<div id="filter_delete"><!--
<wfs:Transaction xmlns:wfs="http://www.opengis.net/wfs" service="WFS" version="1.0.0">
    <wfs:Delete typeName="feature:type" xmlns:feature="http://namespace.org">
        <ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
            <ogc:BBOX>
                <gml:Box xmlns:gml="http://www.opengis.net/gml" srsName="EPSG:4326">
                    <gml:coordinates decimal="." cs="," ts=" ">-5,-5 5,5</gml:coordinates>
                </gml:Box>
            </ogc:BBOX>
        </ogc:Filter>
    </wfs:Delete>
</wfs:Transaction>
--></div>
<div id="query_response"><!--
<?xml version="1.0" encoding="UTF-8"?>
<wfs:FeatureCollection xmlns:ogc="http://www.opengis.net/ogc" xmlns:wfs="http://www.opengis.net/wfs" xmlns:topp="http://www.openplans.org/topp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ows="http://www.opengis.net/ows" xmlns:gml="http://www.opengis.net/gml" xmlns:xlink="http://www.w3.org/1999/xlink"><gml:boundedBy><gml:Envelope srsDimension="2" srsName="urn:x-ogc:def:crs:EPSG:4326"><gml:lowerCorner>5450000.0 500000.0</gml:lowerCorner><gml:upperCorner>5450000.0 540000.0</gml:upperCorner></gml:Envelope></gml:boundedBy><gml:featureMembers><topp:tasmania_roads gml:id="tasmania_roads.1"><gml:boundedBy><gml:Envelope srsDimension="2" srsName="urn:x-ogc:def:crs:EPSG:4326"><gml:lowerCorner>5450000.0 500000.0</gml:lowerCorner><gml:upperCorner>5450000.0 540000.0</gml:upperCorner></gml:Envelope></gml:boundedBy><topp:geom><gml:MultiLineString srsDimension="2" srsName="urn:x-ogc:def:crs:EPSG:4326"><gml:lineStringMember><gml:LineString><gml:posList>5450000.0 500000.0 5450000.0 540000.0</gml:posList></gml:LineString></gml:lineStringMember></gml:MultiLineString></topp:geom><topp:TYPE>street</topp:TYPE></topp:tasmania_roads></gml:featureMembers></wfs:FeatureCollection>
--></div>
</body>
</html>