content: /*
   * Copyright 2013 Hannes Janetzek
   * Copyright 2017 Andrey Novikov
   * Copyright 2017-2018 devemux86
   * Copyright 2019 Gustl22
   *
   * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
   *
   * This program is free software: you can redistribute it and/or modify it under the
   * terms of the GNU Lesser General Public License as published by the Free Software
   * Foundation, either version 3 of the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful, but WITHOUT ANY
   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
   * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public License along with
   * this program. If not, see <http://www.gnu.org/licenses/>.
   */
  package org.oscim.layers.tile.bitmap;
  
  import org.oscim.core.MapPosition;
  import org.oscim.event.Event;
  import org.oscim.layers.tile.TileLayer;
  import org.oscim.layers.tile.TileLoader;
  import org.oscim.layers.tile.TileManager;
  import org.oscim.layers.tile.VectorTileRenderer;
  import org.oscim.map.Map;
  import org.oscim.renderer.bucket.TextureItem.TexturePool;
  import org.oscim.tiling.TileSource;
  import org.oscim.utils.FastMath;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  public class BitmapTileLayer extends TileLayer {
  
      protected static final Logger log = LoggerFactory.getLogger(BitmapTileLayer.class);
  
      private static final int CACHE_LIMIT = 40;
  
      protected final TileSource mTileSource;
  
      /**
       * Bitmap alpha in range 0 to 1.
       */
      private float mBitmapAlpha = 1.0f;
  
      public static class FadeStep {
          public final double scaleStart, scaleEnd;
          public final double zoomStart, zoomEnd;
          public final float alphaStart, alphaEnd;
  
          /**
           * @param zoomStart  the zoom start in range {@value org.oscim.map.Viewport#MIN_ZOOM_LEVEL} to {@value org.oscim.map.Viewport#MAX_ZOOM_LEVEL}
           * @param zoomEnd    the zoom end, must be greater than zoom start
           * @param alphaStart the alpha start value in range 0 to 1
           * @param alphaEnd   the alpha end value in range 0 to 1
           */
          public FadeStep(int zoomStart, int zoomEnd, float alphaStart, float alphaEnd) {
              if (zoomEnd < zoomStart)
                  throw new IllegalArgumentException("zoomEnd must be larger than zoomStart");
              this.scaleStart = 1 << zoomStart;
              this.scaleEnd = 1 << zoomEnd;
              this.zoomStart = zoomStart;
              this.zoomEnd = zoomEnd;
              this.alphaStart = alphaStart;
              this.alphaEnd = alphaEnd;
          }
  
          public FadeStep(double scaleStart, double scaleEnd, float alphaStart, float alphaEnd) {
              if (scaleEnd < scaleStart)
                  throw new IllegalArgumentException("scaleEnd must be larger than scaleStart");
              this.scaleStart = scaleStart;
              this.scaleEnd = scaleEnd;
              this.zoomStart = Math.log(scaleStart) / Math.log(2);
              this.zoomEnd = Math.log(scaleEnd) / Math.log(2);
              this.alphaStart = alphaStart;
              this.alphaEnd = alphaEnd;
          }
      }
  
      public BitmapTileLayer(Map map, TileSource tileSource) {
          this(map, tileSource, CACHE_LIMIT);
      }
  
      public BitmapTileLayer(Map map, TileSource tileSource, float bitmapAlpha) {
          this(map, tileSource, CACHE_LIMIT, bitmapAlpha);
      }
  
      public BitmapTileLayer(Map map, TileSource tileSource, int cacheLimit) {
          this(map, tileSource, cacheLimit, tileSource.getAlpha());
      }
  
      public BitmapTileLayer(Map map, TileSource tileSource, int cacheLimit, float bitmapAlpha) {
          super(map,
                  new TileManager(map, cacheLimit),
                  new VectorTileRenderer());
  
          mTileManager.setZoomLevel(tileSource.getZoomLevelMin(),
                  tileSource.getZoomLevelMax());
  
          mTileSource = tileSource;
          setBitmapAlpha(bitmapAlpha, false);
          initLoader(getNumLoaders());
          setFade(map.getMapPosition());
      }
  
      public void setBitmapAlpha(float bitmapAlpha, boolean redraw) {
          mBitmapAlpha = FastMath.clamp(bitmapAlpha, 0f, 1f);
          tileRenderer().setBitmapAlpha(mBitmapAlpha);
          if (redraw)
              map().updateMap(true);
      }
  
      @Override
      public void onMapEvent(Event event, MapPosition pos) {
          super.onMapEvent(event, pos);
  
          if (event != Map.POSITION_EVENT)
              return;
  
          setFade(pos);
      }
  
      private void setFade(MapPosition pos) {
          FadeStep[] fade = mTileSource.getFadeSteps();
  
          if (fade == null) {
              //mRenderLayer.setBitmapAlpha(1);
              return;
          }
  
          float alpha = mBitmapAlpha;
          for (FadeStep f : fade) {
              if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
                  continue;
  
              if (f.alphaStart == f.alphaEnd) {
                  alpha = f.alphaStart;
                  break;
              }
              // interpolate alpha between start and end
              alpha = (float) (f.alphaStart + (pos.getZoom() - f.zoomStart) * (f.alphaEnd - f.alphaStart) / (f.zoomEnd - f.zoomStart));
              break;
          }
  
          alpha = FastMath.clamp(alpha, 0f, 1f) * mBitmapAlpha;
          tileRenderer().setBitmapAlpha(alpha);
      }
  
      @Override
      protected TileLoader createLoader() {
          return new BitmapTileLoader(this, mTileSource);
      }
  
      @Override
      public void onDetach() {
          super.onDetach();
          pool.clear();
      }
  
      static final int POOL_FILL = 20;
  
      /**
       * pool shared by TextLayers
       */
      final TexturePool pool = new TexturePool(POOL_FILL) {
  
          //        int sum = 0;
          //
          //        public TextureItem release(TextureItem item) {
          //            log.debug(getFill() + " " + sum + " release tex " + item.id);
          //            return super.release(item);
          //        };
          //
          //        public synchronized TextureItem get() {
          //            log.debug(getFill() + " " + sum + " get tex ");
          //
          //            return super.get();
          //        };
          //
          //        protected TextureItem createItem() {
          //            log.debug(getFill() + " " + (sum++) + " create tex ");
          //
          //            return super.createItem();
          //        };
          //
          //        protected void freeItem(TextureItem t) {
          //            log.debug(getFill() + " " + (sum--) + " free tex ");
          //            super.freeItem(t);
          //
          //        };
      };
  
  }
  