import { Ellipsoid } from "../../Source/Cesium.js";
import { GeographicTilingScheme } from "../../Source/Cesium.js";
import { Math as CesiumMath } from "../../Source/Cesium.js";
import { Rectangle } from "../../Source/Cesium.js";
import { Request } from "../../Source/Cesium.js";
import { RequestScheduler } from "../../Source/Cesium.js";
import { Resource } from "../../Source/Cesium.js";
import { WebMercatorProjection } from "../../Source/Cesium.js";
import { WebMercatorTilingScheme } from "../../Source/Cesium.js";
import { GetFeatureInfoFormat } from "../../Source/Cesium.js";
import { Imagery } from "../../Source/Cesium.js";
import { ImageryLayer } from "../../Source/Cesium.js";
import { ImageryProvider } from "../../Source/Cesium.js";
import { ImageryState } from "../../Source/Cesium.js";
import { UrlTemplateImageryProvider } from "../../Source/Cesium.js";
import pollToPromise from "../pollToPromise.js";
import { when } from "../../Source/Cesium.js";

describe("Scene/UrlTemplateImageryProvider", function () {
  beforeEach(function () {
    RequestScheduler.clearForSpecs();
  });

  afterEach(function () {
    Resource._Implementations.createImage =
      Resource._DefaultImplementations.createImage;
  });

  it("conforms to ImageryProvider interface", function () {
    expect(UrlTemplateImageryProvider).toConformToInterface(ImageryProvider);
  });

  it("requires the url to be specified", function () {
    function createWithoutUrl() {
      return new UrlTemplateImageryProvider({});
    }
    expect(createWithoutUrl).toThrowDeveloperError();
  });

  it("resolves readyPromise", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "made/up/tms/server/",
    });

    return provider.readyPromise.then(function (result) {
      expect(result).toBe(true);
      expect(provider.ready).toBe(true);
    });
  });

  it("resolves readyPromise with Resource", function () {
    var resource = new Resource({
      url: "made/up/tms/server/",
    });

    var provider = new UrlTemplateImageryProvider({
      url: resource,
    });

    return provider.readyPromise.then(function (result) {
      expect(result).toBe(true);
      expect(provider.ready).toBe(true);
    });
  });

  it("returns valid value for hasAlphaChannel", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "made/up/tms/server/",
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      expect(typeof provider.hasAlphaChannel).toBe("boolean");
    });
  });

  it("requestImage returns a promise for an image and loads it for cross-origin use", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "made/up/tms/server/{Z}/{X}/{reverseY}",
    });

    expect(provider.url).toEqual("made/up/tms/server/{Z}/{X}/{reverseY}");

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      expect(provider.tileWidth).toEqual(256);
      expect(provider.tileHeight).toEqual(256);
      expect(provider.maximumLevel).toBeUndefined();
      expect(provider.minimumLevel).toBe(0);
      expect(provider.tilingScheme).toBeInstanceOf(WebMercatorTilingScheme);
      expect(provider.rectangle).toEqual(
        new WebMercatorTilingScheme().rectangle
      );

      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(0, 0, 0).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("when no credit is supplied, the provider has no logo", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "made/up/tms/server",
    });
    expect(provider.credit).toBeUndefined();
  });

  it("turns the supplied credit into a logo", function () {
    var providerWithCredit = new UrlTemplateImageryProvider({
      url: "made/up/gms/server",
      credit: "Thanks to our awesome made up source of this imagery!",
    });
    expect(providerWithCredit.credit).toBeDefined();
  });

  it("rectangle passed to constructor does not affect tile numbering", function () {
    var rectangle = new Rectangle(0.1, 0.2, 0.3, 0.4);
    var provider = new UrlTemplateImageryProvider({
      url: "made/up/tms/server/{z}/{x}/{reverseY}",
      rectangle: rectangle,
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      expect(provider.tileWidth).toEqual(256);
      expect(provider.tileHeight).toEqual(256);
      expect(provider.maximumLevel).toBeUndefined();
      expect(provider.minimumLevel).toBe(0);
      expect(provider.tilingScheme).toBeInstanceOf(WebMercatorTilingScheme);
      expect(provider.rectangle).toEqualEpsilon(
        rectangle,
        CesiumMath.EPSILON14
      );
      expect(provider.tileDiscardPolicy).toBeUndefined();

      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toContain("/0/0/0");

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(0, 0, 0).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("uses minimumLevel and maximumLevel passed to constructor", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "made/up/tms/server",
      minimumLevel: 1,
      maximumLevel: 5,
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      expect(provider.minimumLevel).toEqual(1);
      expect(provider.maximumLevel).toEqual(5);
    });
  });

  it("raises error event when image cannot be loaded", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "made/up/tms/server",
    });

    var layer = new ImageryLayer(provider);

    var tries = 0;
    provider.errorEvent.addEventListener(function (error) {
      expect(error.timesRetried).toEqual(tries);
      ++tries;
      if (tries < 3) {
        error.retry = true;
      }
      setTimeout(function () {
        RequestScheduler.update();
      }, 1);
    });

    Resource._Implementations.createImage = function (
      request,
      crossOrigin,
      deferred
    ) {
      if (tries === 2) {
        // Succeed after 2 tries
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      } else {
        // fail
        setTimeout(function () {
          deferred.reject();
        }, 1);
      }
    };

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      var imagery = new Imagery(layer, 0, 0, 0);
      imagery.addReference();
      layer._requestImagery(imagery);
      RequestScheduler.update();

      return pollToPromise(function () {
        return imagery.state === ImageryState.RECEIVED;
      }).then(function () {
        expect(imagery.image).toBeImageOrImageBitmap();
        expect(tries).toEqual(2);
        imagery.releaseReference();
      });
    });
  });

  it("evaluation of pattern X Y reverseX reverseY Z reverseZ", function () {
    var provider = new UrlTemplateImageryProvider({
      url:
        "made/up/tms/server/{z}/{reverseZ}/{reverseY}/{y}/{reverseX}/{x}.PNG",
      tilingScheme: new GeographicTilingScheme(),
      maximumLevel: 6,
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqual("made/up/tms/server/2/3/2/1/4/3.PNG");

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(3, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("evaluation of schema zero padding for X Y Z as 0000", function () {
    var provider = new UrlTemplateImageryProvider({
      url:
        "made/up/tms/server/{z}/{reverseZ}/{reverseY}/{y}/{reverseX}/{x}.PNG",
      urlSchemeZeroPadding: {
        "{x}": "0000",
        "{y}": "0000",
        "{z}": "0000",
      },
      tilingScheme: new GeographicTilingScheme(),
      maximumLevel: 6,
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqual(
          "made/up/tms/server/0002/3/2/0001/4/0003.PNG"
        );

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(3, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("evaluation of schema zero padding for reverseX reverseY reverseZ as 0000", function () {
    var provider = new UrlTemplateImageryProvider({
      url:
        "made/up/tms/server/{z}/{reverseZ}/{reverseY}/{y}/{reverseX}/{x}.PNG",
      urlSchemeZeroPadding: {
        "{reverseX}": "0000",
        "{reverseY}": "0000",
        "{reverseZ}": "0000",
      },
      tilingScheme: new GeographicTilingScheme(),
      maximumLevel: 6,
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqual(
          "made/up/tms/server/2/0003/0002/1/0004/3.PNG"
        );

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(3, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("evaluation of schema zero padding for x y z as 0000 and large x and y", function () {
    var provider = new UrlTemplateImageryProvider({
      url:
        "made/up/tms/server/{z}/{reverseZ}/{reverseY}/{y}/{reverseX}/{x}.PNG",
      urlSchemeZeroPadding: {
        "{x}": "0000",
        "{y}": "0000",
        "{z}": "0000",
      },
      tilingScheme: new GeographicTilingScheme(),
      maximumLevel: 6,
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqual(
          "made/up/tms/server/0005/0/21/0010/51/0012.PNG"
        );

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(12, 10, 5).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("evaluates pattern northDegrees", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "{northDegrees}",
      tilingScheme: new GeographicTilingScheme(),
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqualEpsilon(45.0, CesiumMath.EPSILON11);

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(3, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("evaluates pattern southDegrees", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "{southDegrees}",
      tilingScheme: new GeographicTilingScheme(),
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqualEpsilon(0.0, CesiumMath.EPSILON11);

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(3, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("evaluates pattern eastDegrees", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "{eastDegrees}",
      tilingScheme: new GeographicTilingScheme(),
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqualEpsilon(0.0, CesiumMath.EPSILON11);

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(3, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("evaluates pattern westDegrees", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "{westDegrees}",
      tilingScheme: new GeographicTilingScheme(),
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqualEpsilon(-45.0, CesiumMath.EPSILON11);

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(3, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("evaluates pattern northProjected", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "{northProjected}",
      tilingScheme: new WebMercatorTilingScheme(),
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqualEpsilon(
          (Math.PI * Ellipsoid.WGS84.maximumRadius) / 2.0,
          CesiumMath.EPSILON11
        );

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(3, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("evaluates pattern southProjected", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "{southProjected}",
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqualEpsilon(
          (Math.PI * Ellipsoid.WGS84.maximumRadius) / 2.0,
          CesiumMath.EPSILON11
        );

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(3, 0, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("evaluates pattern eastProjected", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "{eastProjected}",
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqualEpsilon(
          (-Math.PI * Ellipsoid.WGS84.maximumRadius) / 2.0,
          CesiumMath.EPSILON11
        );

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(0, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("evaluates pattern westProjected", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "{westProjected}",
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqualEpsilon(
          (-Math.PI * Ellipsoid.WGS84.maximumRadius) / 2.0,
          CesiumMath.EPSILON11
        );

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(1, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("evalutes multiple coordinate patterns", function () {
    var provider = new UrlTemplateImageryProvider({
      url:
        "{westDegrees} {westProjected} {southProjected} {southDegrees} {eastProjected} {eastDegrees} {northDegrees} {northProjected}",
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqual(
          "-90 " +
            (-Math.PI * Ellipsoid.WGS84.maximumRadius) / 2.0 +
            " " +
            "0 " +
            "0 " +
            "0 " +
            "0 " +
            CesiumMath.toDegrees(
              WebMercatorProjection.mercatorAngleToGeodeticLatitude(Math.PI / 2)
            ) +
            " " +
            (Math.PI * Ellipsoid.WGS84.maximumRadius) / 2.0
        );

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(1, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("evaluates pattern s", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "{s}",
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(["a", "b", "c"].indexOf(request.url)).toBeGreaterThanOrEqualTo(
          0
        );

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(3, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("uses custom subdomain string", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "{s}",
      subdomains: "123",
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(["1", "2", "3"].indexOf(request.url)).toBeGreaterThanOrEqualTo(
          0
        );

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(3, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("uses custom subdomain array", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "{s}",
      subdomains: ["foo", "bar"],
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(["foo", "bar"].indexOf(request.url)).toBeGreaterThanOrEqualTo(0);

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(3, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  it("uses custom tags", function () {
    var provider = new UrlTemplateImageryProvider({
      url: "made/up/tms/server/{custom1}/{custom2}/{z}/{y}/{x}.PNG",
      tilingScheme: new GeographicTilingScheme(),
      maximumLevel: 6,
      customTags: {
        custom1: function () {
          return "foo";
        },
        custom2: function () {
          return "bar";
        },
      },
    });

    return pollToPromise(function () {
      return provider.ready;
    }).then(function () {
      spyOn(Resource._Implementations, "createImage").and.callFake(function (
        request,
        crossOrigin,
        deferred
      ) {
        expect(request.url).toEqual("made/up/tms/server/foo/bar/2/1/3.PNG");

        // Just return any old image.
        Resource._DefaultImplementations.createImage(
          new Request({ url: "Data/Images/Red16x16.png" }),
          crossOrigin,
          deferred
        );
      });

      return provider.requestImage(3, 1, 2).then(function (image) {
        expect(Resource._Implementations.createImage).toHaveBeenCalled();
        expect(image).toBeImageOrImageBitmap();
      });
    });
  });

  describe("pickFeatures", function () {
    it("returns undefined when enablePickFeatures is false", function () {
      var provider = new UrlTemplateImageryProvider({
        url: "foo/bar",
        pickFeaturesUrl: "foo/bar",
        getFeatureInfoFormats: [
          new GetFeatureInfoFormat("json", "application/json"),
          new GetFeatureInfoFormat("xml", "text/xml"),
        ],
        enablePickFeatures: false,
      });

      return pollToPromise(function () {
        return provider.ready;
      }).then(function () {
        expect(provider.pickFeatures(0, 0, 0, 0.0, 0.0)).toBeUndefined();
      });
    });

    it("does not return undefined when enablePickFeatures is subsequently set to true", function () {
      var provider = new UrlTemplateImageryProvider({
        url: "foo/bar",
        pickFeaturesUrl: "foo/bar",
        getFeatureInfoFormats: [
          new GetFeatureInfoFormat("json", "application/json"),
          new GetFeatureInfoFormat("xml", "text/xml"),
        ],
        enablePickFeatures: false,
      });

      provider.enablePickFeatures = true;

      return pollToPromise(function () {
        return provider.ready;
      }).then(function () {
        expect(provider.pickFeatures(0, 0, 0, 0.0, 0.0)).not.toBeUndefined();
      });
    });

    it("returns undefined when enablePickFeatures is initialized as true and set to false", function () {
      var provider = new UrlTemplateImageryProvider({
        url: "foo/bar",
        pickFeaturesUrl: "foo/bar",
        getFeatureInfoFormats: [
          new GetFeatureInfoFormat("json", "application/json"),
          new GetFeatureInfoFormat("xml", "text/xml"),
        ],
        enablePickFeatures: true,
      });

      provider.enablePickFeatures = false;

      return pollToPromise(function () {
        return provider.ready;
      }).then(function () {
        expect(provider.pickFeatures(0, 0, 0, 0.0, 0.0)).toBeUndefined();
      });
    });
  });

  it("throws if tileWidth called before provider is ready", function () {
    var provider = new UrlTemplateImageryProvider(when.defer());

    expect(function () {
      return provider.tileWidth();
    }).toThrowDeveloperError();
  });

  it("throws if tileHeight called before provider is ready", function () {
    var provider = new UrlTemplateImageryProvider(when.defer());

    expect(function () {
      return provider.tileHeight();
    }).toThrowDeveloperError();
  });

  it("throws if maximumLevel called before provider is ready", function () {
    var provider = new UrlTemplateImageryProvider(when.defer());

    expect(function () {
      return provider.maximumLevel();
    }).toThrowDeveloperError();
  });

  it("throws if minimumLevel called before provider is ready", function () {
    var provider = new UrlTemplateImageryProvider(when.defer());

    expect(function () {
      return provider.minimumLevel();
    }).toThrowDeveloperError();
  });

  it("throws if tilingScheme called before provider is ready", function () {
    var provider = new UrlTemplateImageryProvider(when.defer());

    expect(function () {
      return provider.tilingScheme();
    }).toThrowDeveloperError();
  });

  it("throws if rectangle called before provider is ready", function () {
    var provider = new UrlTemplateImageryProvider(when.defer());

    expect(function () {
      return provider.rectangle();
    }).toThrowDeveloperError();
  });

  it("throws if tileDiscardPolicy called before provider is ready", function () {
    var provider = new UrlTemplateImageryProvider(when.defer());

    expect(function () {
      return provider.tileDiscardPolicy();
    }).toThrowDeveloperError();
  });

  it("throws if credit called before provider is ready", function () {
    var provider = new UrlTemplateImageryProvider(when.defer());

    expect(function () {
      return provider.credit();
    }).toThrowDeveloperError();
  });

  it("throws if hasAlphaChannel called before provider is ready", function () {
    var provider = new UrlTemplateImageryProvider(when.defer());

    expect(function () {
      return provider.hasAlphaChannel();
    }).toThrowDeveloperError();
  });

  it("throws if getTileCredits called before provider is ready", function () {
    var provider = new UrlTemplateImageryProvider(when.defer());

    expect(function () {
      return provider.getTileCredits();
    }).toThrowDeveloperError();
  });

  it("throws if requestImage called before provider is ready", function () {
    var provider = new UrlTemplateImageryProvider(when.defer());

    expect(function () {
      return provider.requestImage();
    }).toThrowDeveloperError();
  });

  it("throws if pickFeatures called before provider is ready", function () {
    var provider = new UrlTemplateImageryProvider(when.defer());

    expect(function () {
      return provider.pickFeatures();
    }).toThrowDeveloperError();
  });
});
