package amodeus.socket;

import java.io.File;
import java.util.Objects;
import amodeus.amodeus.analysis.Analysis;
import amodeus.amodeus.options.ScenarioOptions;
import amodeus.amodeus.options.ScenarioOptionsBase;
import amodeus.amodeus.prep.LegCount;
import amodeus.amodeus.util.io.MultiFileTools;
import amodeus.amodeus.util.matsim.xml.ConfigDispatcherChanger;
import amodeus.amodeus.util.matsim.xml.ConfigVehiclesChanger;
import amodeus.amodeus.util.net.StringServerSocket;
import amodeus.amodeus.util.net.StringSocket;
import amodeus.amodeus.video.VideoGenerator;
import org.matsim.amodeus.config.AmodeusModeConfig;
import amodeus.socket.core.ScoreParameters;
import amodeus.socket.core.SocketDispatcherHost;
import amodeus.socket.core.SocketScoreElement;
import ch.ethz.idsc.tensor.RealScalar;
import ch.ethz.idsc.tensor.Scalar;
import ch.ethz.idsc.tensor.Tensor;
import ch.ethz.idsc.tensor.Tensors;
import ch.ethz.idsc.tensor.red.Total;
import ch.ethz.idsc.tensor.sca.Round;

// TODO refactor and shorten @clruch
/**
 * host that runs in container.
 * a client can connect to a running host via TCP/IP
 *
 * Usage:
 * java -cp target/amod-VERSION.jar amod.socket.SocketHost [city]
 */
public enum SocketHost {
    ;

    public static final int PORT = 9382;

    private static final String ENV_SCENARIO = "SCENARIO";

    private static final String ENV_FLEET_SIZE = "FLEET_SIZE";

    private static final String ENV_REQUESTS_SIZE = "REQUESTS_SIZE";

    private static final String ENV_VIDEO_EXPORT = "VIDEO_EXPORT";

    public static void main(String[] args) throws Exception {
        File workingDirectory = MultiFileTools.getDefaultWorkingDirectory();
        run(workingDirectory);
    }

    public static void run(File workingDirectory) throws Exception {
        System.out.println("Using scenario directory: " + workingDirectory);
        StringSocket stringSocket = null;
        /**
         * open String server and wait for initial command
         */
        try (StringServerSocket serverSocket = new StringServerSocket(PORT)) {
            stringSocket = serverSocket.getSocketWait();
            // only allow one connection
            serverSocket.close();
            String readLine = stringSocket.readLine();
            Tensor config = Tensors.fromString(readLine);
            System.out.println("SocketHost config: " + config);
            Thread.slee

p(1000);
            String scenarioTag = config.Get(0).toString();
            {
                String env = System.getenv(ENV_SCENARIO);
                if (Objects.nonNull(env))
                    env = scenarioTag;
            }
            /**
             * download the chosen scenario
             */
            SocketScenarioResource.extract(scenarioTag, workingDirectory);
            /**
             * setup environment variables
             */
            StaticHelper.setup();
            /**
             * run first part of scenario preparer
             */
            SocketPreparer preparer = new SocketPreparer(workingDirectory);
            /**
             * get number of requests in population
             */
            long numReq = LegCount.of(preparer.getPopulation(), AmodeusModeConfig.DEFAULT_MODE);
            Scalar nominalFleetSize = Round.of(RealScalar.of(numReq).multiply(ScoreParameters.GLOBAL.gamma));
            Tensor initialInfo = Tensors.of(RealScalar.of(numReq), preparer.getBoundingBox(), nominalFleetSize);
            /**
             * send initial data: {numberRequests,boundingBox}
             */
            stringSocket.writeln(initialInfo);
            /**
             * get additional information
             */
            String readLine2 = stringSocket.readLine();
            Tensor config2 = Tensors.fromString(readLine2);
            int numReqDes = config2.Get(0).number().intValue();
            int fleetSize = config2.Get(1).number().intValue();
            {
                String env = System.getenv(ENV_REQUESTS_SIZE);
                if (Objects.nonNull(env))
                    try {
                        numReqDes = Integer.parseInt(env);
                    } catch (Exception exception) {
                        exception.printStackTrace();
                    }
            }
            {
                String env = System.getenv(ENV_FLEET_SIZE);
                if (Objects.nonNull(env))
                    try {
                        fleetSize = Integer.parseInt(env);
                    } catch (Exception exception) {
                        exception.printStackTrace();
                    }
            }
            /**
             * run second part of preparer
             */
            preparer.run2(numReqDes);
            /**
             * run with socket dispatcher
             */
            ScenarioOptions scenarioOptions = new ScenarioOptions(workingDirectory, ScenarioOptionsBase.getDefault());
            String simConfigPath = scenarioOptions.getSimulationConfigName();
            ConfigDispatcherChanger.change(simConfigPath, SocketDispatcherHost.class.getSimpleName());
            ConfigVehiclesChanger.change(simConfigPath, fleetSize);
            SocketServer socketServer = new SocketServer();
            socketServer.simulate(stringSocket, numReqDes, workingDirectory);
            /**
             * send empty tensor "{}" to stop
             */
            stringSocket.writeln(Tensors.empty());
            /**
             * analyze and send final score
             */
            Analysis analysis = //
            Analysis.//
            setup(//
            socketServer.getScenarioOptions(), socketServer.getOutputDirectory(), socketServer.getNetwork(), preparer.getDatabase());
            SocketScoreElement socketScoreElement = new SocketScoreElement(fleetSize, numReqDes, preparer.getDatabase());
            analysis.addAnalysisElement(socketScoreElement);
            SocketExport socketExport = new SocketExport(socketScoreElement);
            analysis.addAnalysisExport(socketExport);
            SocketHtmlReport socketHtmlReport = new SocketHtmlReport(socketScoreElement);
            analysis.addHtmlElement(socketHtmlReport);
            analysis.run();
            {
                /**
                 * create a video if environment variable is set
                 */
                String env = System.getenv(ENV_VIDEO_EXPORT);
                if (Objects.nonNull(env) && env.equalsIgnoreCase("true"))
                    new VideoGenerator(workingDirectory).start();
            }
            /**
             * send final score,
             * {total waiting time, total distance with customer, total empty distance}
             */
            stringSocket.writeln(Total.of(socketScoreElement.getScoreDiffHistory()));
        } catch (Exception exception) {
            shutdown(stringSocket);
            throw exception;
        }
    }

    private static void shutdown(StringSocket stringSocket) throws Exception {
        if (Objects.nonNull(stringSocket)) {
            /**
             * send empty tensor "{}" to stop
             */
            stringSocket.writeln(Tensors.empty());
            /**
             * send fictitious costs
             */
            stringSocket.writeln(StaticHelper.FAILURE_SCORE);
        }
    }
}


@Override
    public Object get(Object key)

package org.flowable.common.engine.impl.scripting;

import org.flowable.common.engine.impl.AbstractEngineConfiguration;
import org.flowable.variable.api.delegate.VariableScope;

/**
 * @author Tom Baeyens
 */
public class BeansResolverFactory implements ResolverFactory, Resolver {

    protected AbstractEngineConfiguration engineConfiguration;

    @Override
    public Resolver createResolver(AbstractEngineConfiguration processEngineConfiguration, VariableScope variableScope) {
        this.engineConfiguration = processEngineConfiguration;
        return this;
    }

    @Override
    public boolean containsKey(Object key) {
        return engineConfiguration.getBeans().containsKey(key);
    }

{
        return engineConfiguration.getBeans().get(key);
    }
}


{
        return engineConfiguration.getBeans().get(key);
    }

package org.flowable.common.engine.impl.scripting;

import org.flowable.common.engine.impl.AbstractEngineConfiguration;
import org.flowable.variable.api.delegate.VariableScope;

/**
 * @author Tom Baeyens
 */
public class BeansResolverFactory implements ResolverFactory, Resolver {

    protected AbstractEngineConfiguration engineConfiguration;

    @Override
    public Resolver createResolver(AbstractEngineConfiguration processEngineConfiguration, VariableScope variableScope) {
        this.engineConfiguration = processEngineConfiguration;
        return this;
    }

    @Override
    public boolean containsKey(Object key) {
        return engineConfiguration.getBeans().containsKey(key);
    }

    @Override
    public Object get(Object key)


package org.flowable.common.engine.impl.scripting;

import org.flowable.common.engine.impl.AbstractEngineConfiguration;
import org.flowable.variable.api.delegate.VariableScope;

/**
 * @author Tom Baeyens
 */
public class BeansResolverFactory implements ResolverFactory, Resolver {

    protected AbstractEngineConfiguration engineConfiguration;

    @Override
    public Resolver createResolver(AbstractEngineConfiguration processEngineConfiguration, VariableScope variableScope) {
        this.engineConfiguration = processEngineConfiguration;
        return this;
    }

    @Override
    public boolean containsKey(Object key) {
        return engineConfiguration.getBeans().containsKey(key);
    }

    @Override
    public Object get(Object key) {
        return engineConfiguration.getBe


.common.engine.impl.scripting;

import org.flowable.common.engine.impl.AbstractEngineConfiguration;
import org.flowable.variable.api.delegate.VariableScope;

/**
 * @author Tom Baeyens
 */
public class BeansResolverFactory implements ResolverFactory, Resolver {

    protected AbstractEngineConfiguration engineConfiguration;

    @Override
    public Resolver createResolver(AbstractEngineConfiguration processEngineConfiguration, VariableScope variableScope) {
        this.engineConfiguration = processEngineConfiguration;
        return this;
    }

    @Override
    public boolean containsKey(Object key) {
        return engineConfiguration.getBeans().containsKey(key);
    }

    @Override
    public Object get(Object key) {
        return engineConfiguration.getBeans().get(key);
    }
}


@Override
    public void call(AsyncEmitter<Float> emitter)

package io.github.plastix.forage.data.sensor;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.annotation.NonNull;
import android.view.WindowManager;
import javax.inject.Inject;
import io.github.plastix.forage.util.AngleUtils;
import rx.AsyncEmitter;
import rx.functions.Action1;

public class AzimuthAsyncEmitter implements Action1<AsyncEmitter<Float>> {

    private SensorManager sensorManager;

    private WindowManager windowManager;

    private Sensor compass;

    private float[] orientation;

    private float[] rMat;

    @Inject
    public AzimuthAsyncEmitter(@NonNull SensorManager sensorManager, @NonNull WindowManager windowManager) {
        this.sensorManager = sensorManager;
        this.windowManager = windowManager;
        this.orientation = new float[3];
        this.rMat = new float[9];
        this.compass = null;
    }

{
        compass = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
        if (compass != null) {
            SensorEventListener sensorEventListener = new SensorEventListener() {

                @Override
                public void onSensorChanged(SensorEvent event) {
                    if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
                        // Calculate the rotation matrix
                        SensorManager.getRotationMatrixFromVector(rMat, event.values);
                        // Compass direction is result[0]
                        float[] result = SensorManager.getOrientation(rMat, orientation);
                        float azimuth = (float) (Math.toDegrees(result[0]));
                        azimuth += AngleUtils.getRotationOffset(windowManager);
                        emitter.onNext(azimuth);
                    }
                }

                @Override
                public void onAccuracyChanged(Sensor sensor, int i) {
                    // No op
                }
            };
            sensorManager.registerListener(sensorEventListener, compass, SensorManager.SENSOR_DELAY_GAME);
            emitter.setCancellation(() -> sensorManager.unregisterListener(sensorEventListener, compass));
        } else {
            emitter.onError(new SensorUnavailableException("Compass Sensor not available!"));
        }
    }
}


{
                    // No op
                }

package io.github.plastix.forage.data.sensor;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.annotation.NonNull;
import android.view.WindowManager;
import javax.inject.Inject;
import io.github.plastix.forage.util.AngleUtils;
import rx.AsyncEmitter;
import rx.functions.Action1;

public class AzimuthAsyncEmitter implements Action1<AsyncEmitter<Float>> {

    private SensorManager sensorManager;

    private WindowManager windowManager;

    private Sensor compass;

    private float[] orientation;

    private float[] rMat;

    @Inject
    public AzimuthAsyncEmitter(@NonNull SensorManager sensorManager, @NonNull WindowManager windowManager) {
        this.sensorManager = sensorManager;
        this.windowManager = windowManager;
        this.orientation = new float[3];
        this.rMat = new float[9];
        this.compass = null;
    }

    @Override
    public void call(AsyncEmitter<Float> emitter) {
        compass = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
        if (compass != null) {
            SensorEventListener sensorEventListener = new SensorEventListener() {

                @Override
                public void onSensorChanged(SensorEvent event) {
                    if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
                        // Calculate the rotation matrix
                        SensorManager.getRotationMatrixFromVector(rMat, event.values);
                        // Compass direction is result[0]
                        float[] result = SensorManager.getOrientation(rMat, orientation);
                        float azimuth = (float) (Math.toDegrees(result[0]));
                        azimuth += AngleUtils.getRotationOffset(windowManager);
                        emitter.onNext(azimuth);
                    }
                }

                @Override
                public void onAccuracyChanged(Sensor sensor, int i)

            };
            sensorManager.registerListener(sensorEventListener, compass, SensorManager.SENSOR_DELAY_GAME);
            emitter.setCancellation(() -> sensorManager.unregisterListener(sensorEventListener, compass));
        } else {
            emitter.onError(new SensorUnavailableException("Compass Sensor not available!"));
        }
    }
}


package io.github.plastix.forage.data.sensor;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.annotation.NonNull;
import android.view.WindowManager;
import javax.inject.Inject;
import io.github.plastix.forage.util.AngleUtils;
import rx.AsyncEmitter;
import rx.functions.Action1;

public class AzimuthAsyncEmitter implements Action1<AsyncEmitter<Float>> {

    private SensorManager sensorManager;

    private WindowManager windowManager;

    private Sensor compass;

    private float[] orientation;

    private float[] rMat;

    @Inject
    public AzimuthAsyncEmitter(@NonNull SensorManager sensorManager, @NonNull WindowManager windowManager) {
        this.sensorManager = sensorManager;
        this.windowManager = windowManager;
        this.orientation = new float[3];
        this.rMat = new float[9];
        this.compass = null;
    }

    @Override
    public void call(AsyncEmitter<Float> emitter) {
        compass = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
        if (compass != null) {
            SensorEventListener sensorEventListener = new SensorEventListener() {

                @Override
                public void onSensorChanged(SensorEvent event) {

                    if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
                        // Calculate the rotation matrix
                        SensorManager.getRotationMatrixFromVector(rMat, event.values);
                        // Compass direction is result[0]
                        float[] result = SensorManager.getOrientation(rMat, orientation);
                        float azimuth = (float) (Math.toDegrees(result[0]));
                        azimuth += AngleUtils.getRotationOffset(windowManager);
                        emitter.onNext(azimuth);
                    }
                }

                @Override
                public void onAccuracyChanged(Sensor sensor, int i) {
                    // No op
                }
            };
            sensorManager.registerListener(sensorEventListener, compass, SensorManager.SENSOR_DELAY_GAME);
            emitter.setCancellation(() -> sensorManager.unregisterListener(sensorEventListener, compass));
        } else {
            emitter.onError(new SensorUnavailableException("Compass Sensor not available!"));
        }
    }
}


if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
                        // Calculate the rotation matrix
                        SensorManager.getRotationMatrixFromVector(rMat, event.values);
                        // Compass direction is result[0]
                        float[] result = SensorManager.getOrientation(rMat, orientation);
                        float azimuth = (float) (Math.toDegrees(result[0]));
                        azimuth += AngleUtils.getRotationOffset(windowManager);
                        emitter.onNext(azimuth);
                    }

                }

                @Override
                public void onAccuracyChanged(Sensor sensor, int i) {
                    // No op
                }
            };
            sensorManager.registerListener(sensorEventListener, compass, SensorManager.SENSOR_DELAY_GAME);
            emitter.setCancellation(() -> sensorManager.unregisterListener(sensorEventListener, compass));
        } else {
            emitter.onError(new SensorUnavailableException("Compass Sensor not available!"));
        }
    }
}


package io.github.plastix.forage.data.sensor;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.annotation.NonNull;
import android.view.WindowManager;
import javax.inject.Inject;
import io.github.plastix.forage.util.AngleUtils;
import rx.AsyncEmitter;
import rx.functions.Action1;

public class AzimuthAsyncEmitter implements Action1<AsyncEmitter<Float>> {

    private SensorManager sensorManager;

    private WindowManager windowManager;

    private Sensor compass;

    private float[] orientation;

    private float[] rMat;

    @Inject
    public AzimuthAsyncEmitter(@NonNull SensorManager sensorManager, @NonNull WindowManager windowManager) {
        this.sensorManager = sensorManager;
        this.windowManager = windowManager;
        this.orientation = new float[3];
        this.rMat = new float[9];
        this.compass = null;
    }

    @Override
    public void call(AsyncEmitter<Float> emitter) {
        compass = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
        if (compass != null) {
            SensorEventListener sensorEventListener = new SensorEventListener() {

                @Override
                public void onSensorChanged(SensorEvent event) {
                    if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
                        // Calculate the rotation matrix
                        SensorManager.getRotationMatrixFromVector(rMat, event.values);
                        // Compass direction is result[0]
                        float[] result = SensorManager.getOrientation(rMat, orientation);
                        float azimuth = (float) (Math.toDegrees(result[0]));
                        azimuth += AngleUtils.getRotationOffset(windowManager);
                        emitter.onNext(azimuth);
                    }

                @Override
                public void onAccuracyChanged(Sensor sensor, int i) {
                    // No op
                }
            };
            sensorManager.registerListener(sensorEventListener, compass, SensorManager.SENSOR_DELAY_GAME);
            emitter.setCancellation(() -> sensorManager.unregisterListener(sensorEventListener, compass));
        } else {
            emitter.onError(new SensorUnavailableException("Compass Sensor not available!"));
        }
    }
}


package io.github.plastix.forage.data.sensor;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.annotation.NonNull;
import android.view.WindowManager;
import javax.inject.Inject;
import io.github.plastix.forage.util.AngleUtils;
import rx.AsyncEmitter;
import rx.functions.Action1;

public class AzimuthAsyncEmitter implements Action1<AsyncEmitter<Float>> {

    private SensorManager sensorManager;

    private WindowManager windowManager;

    private Sensor compass;

    private float[] orientation;

    private float[] rMat;

    @Inject
    public AzimuthAsyncEmitter(@NonNull SensorManager sensorManager, @NonNull WindowManager windowManager) {
        this.sensorManager = sensorManager;
        this.windowManager = windowManager;
        this.orientation = new float[3];
        this.rMat = new float[9];
        this.compass = null;
    }

    @Override
    public void call(AsyncEmitter<Float> emitter) {
        compass = sensorManager.getDefaultSen

        if (compass != null) {
            SensorEventListener sensorEventListener = new SensorEventListener() {

                @Override
                public void onSensorChanged(SensorEvent event) {
                    if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
                        // Calculate the rotation matrix
                        SensorManager.getRotationMatrixFromVector(rMat, event.values);
                        // Compass direction is result[0]
                        float[] result = SensorManager.getOrientation(rMat, orientation);
                        float azimuth = (float) (Math.toDegrees(result[0]));
                        azimuth += AngleUtils.getRotationOffset(windowManager);
                        emitter.onNext(azimuth);
                    }
                }

                @Override
                public void onAccuracyChanged(Sensor sensor, int i) {
                    // No op
                }
            };
            sensorManager.registerListener(sensorEventListener, compass, SensorManager.SENSOR_DELAY_GAME);
            emitter.setCancellation(() -> sensorManager.unregisterListener(sensorEventListener, compass));
        } else {
            emitter.onError(new SensorUnavailableException("Compass Sensor not available!"));
        }
    }
}


package io.github.plastix.forage.data.sensor;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.annotation.NonNull;
import android.view.WindowManager;
import javax.inject.Inject;
import io.github.plastix.forage.util.AngleUtils;
import rx.AsyncEmitter;
import rx.functions.Action1;

public class AzimuthAsyncEmitter implements Action1<AsyncEmitter<Float>> {

    private SensorM

anager sensorManager;

    private WindowManager windowManager;

    private Sensor compass;

    private float[] orientation;

    private float[] rMat;

    @Inject
    public AzimuthAsyncEmitter(@NonNull SensorManager sensorManager, @NonNull WindowManager windowManager) {
        this.sensorManager = sensorManager;
        this.windowManager = windowManager;
        this.orientation = new float[3];
        this.rMat = new float[9];
        this.compass = null;
    }

    @Override
    public void call(AsyncEmitter<Float> emitter) {
        compass = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
        if (compass != null) {
            SensorEventListener sensorEventListener = new SensorEventListener() {

                @Override
                public void onSensorChanged(SensorEvent event) {
                    if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
                        // Calculate the rotation matrix
                        SensorManager.getRotationMatrixFromVector(rMat, event.values);
                        // Compass direction is result[0]
                        float[] result = SensorManager.getOrientation(rMat, orientation);
                        float azimuth = (float) (Math.toDegrees(result[0]));
                        azimuth += AngleUtils.getRotationOffset(windowManager);
                        emitter.onNext(azimuth);
                    }
                }

                @Override
                public void onAccuracyChanged(Sensor sensor, int i) {
                    // No op
                }
            };
            sensorManager.registerListener(sensorEventListener, compass, SensorManager.SENSOR_DELAY_GAME);
            emitter.setCancellation(() -> sensorManager.unregisterListener(sensorEventListener, compass));
        } else {
            emitter.onError(new SensorUnavailableException("Compass Sensor not available!"));
        }
    }
}


@Override
    public void process() throws MigrationCallbackException

/*
 * All Rights Reserved
 */
package com.emc.storageos.db.client.upgrade.callbacks;

import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.ExportGroup;
import com.emc.storageos.db.client.model.ExportGroup.ExportGroupType;
import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback;
import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException;

/**
 * Migration handler to convert value of type field for an export group, from
 * Exclusive to Initiator.
 */
public class ExportGroupTypeConverter extends BaseCustomMigrationCallback {

    private static final Logger log = LoggerFactory.getLogger(ExportGroupTypeConverter.class);

    private static final String TYPE_FIELD_NAME = "type";

    private static final String OLD_TYPE_VALUE = "Exclusive";

{
        log.info("Handle ExportGroup type conversion");
        DbClient dbClient = getDbClient();
        List<URI> exportGroupURIs = dbClient.queryByType(ExportGroup.class, false);
        Iterator<ExportGroup> exportGroupsIter = dbClient.queryIterativeObjectField(ExportGroup.class, TYPE_FIELD_NAME, exportGroupURIs);
        List<ExportGroup> exportGroups = new ArrayList<ExportGroup>();
        while (exportGroupsIter.hasNext()) {
            ExportGroup exportGroup = exportGroupsIter.next();
            String exportGroupId = exportGroup.getId().toString();
            log.info("Examining ExportGroup (id={}) for upgrade", exportGroupId);
            String type = exportGroup.getType();
            if (type.equals(OLD_TYPE_VALUE)) {
                exportGroup.setType(ExportGroupType.Initiator.name());
                log.info("Reset export group type for export group (id={})", exportGroupId);
                exportGroups.add(exportGroup);
            }
        }
        dbClient.persistObject(exportGroups);
    }
}


        log.info("Handle ExportGroup type conversion");
        DbClient dbClient = getDbClient();

/*
 * All Rights Reserved
 */
package com.emc.storageos.db.client.upgrade.callbacks;

import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.ExportGroup;
import com.emc.storageos.db.client.model.ExportGroup.ExportGroupType;
import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback;
import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException;

/**
 * Migration handler to convert value of type field for an export group, from
 * Exclusive to Initiator.
 */
public class ExportGroupTypeConverter extends BaseCustomMigrationCallback {

    private static final Logger log = LoggerFactory.getLogger(ExportGroupTypeConverter.class);

    private static final String TYPE_FIELD_NAME = "type";

    private static final String OLD_TYPE_VALUE = "Exclusive";

    @Override
    public void process() throws MigrationCallbackException {

        List<URI> exportGroupURIs = dbClient.queryByType(ExportGroup.class, false);
        Iterator<ExportGroup> exportGroupsIter = dbClient.queryIterativeObjectField(ExportGroup.class, TYPE_FIELD_NAME, exportGroupURIs);
        List<ExportGroup> exportGroups = new ArrayList<ExportGroup>();
        while (exportGroupsIter.hasNext()) {
            ExportGroup exportGroup = exportGroupsIter.next();
            String exportGroupId = exportGroup.getId().toString();
            log.info("Examining ExportGroup (id={}) for upgrade", exportGroupId);
            String type = exportGroup.getType();
            if (type.equals(OLD_TYPE_VALUE)) {
                exportGroup.setType(ExportGroupType.Initiator.name());
                log.info("Reset export group type for export group (id={})", exportGroupId);
                exportGroups.add(exportGroup);
            }
        }
        dbClient.persistObject(exportGroups);
    }
}


List<URI> exportGroupURIs = dbClient.queryByType(ExportGroup.class, false);
        Iterator<ExportGroup> exportGroupsIter = dbClient.queryIterativeObjectField(ExportGroup.class, TYPE_FIELD_NAME, exportGroupURIs);
        List<ExportGroup> exportGroups = new ArrayList<ExportGroup>();

/*
 * All Rights Reserved
 */
package com.emc.storageos.db.client.upgrade.callbacks;

import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.ExportGroup;
import com.emc.storageos.db.client.model.ExportGroup.ExportGroupType;
import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback;
import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException;

/**
 * Migration handler to convert value of type field for an export group, from
 * Exclusive to Initiator.
 */
public class ExportGroupTypeConverter extends BaseCustomMigrationCallback {

    private static final Logger log = LoggerFactory.getLogger(ExportGroupTypeConverter.class);

    private static final String TYPE_FIELD_NAME = "type";

    private static final String OLD_TYPE_VALUE = "Exclusive";

    @Override
    public void process() throws MigrationCallbackException {
        log.info("Handle ExportGroup type conversion");
        DbClient dbClient = getDbClient();

        while (exportGroupsIter.hasNext()) {
            ExportGroup exportGroup = exportGroupsIter.next();
            String exportGroupId = exportGroup.getId().toString();
            log.info("Examining ExportGroup (id={}) for upgrade", exportGroupId);
            String type = exportGroup.getType();
            if (type.equals(OLD_TYPE_VALUE)) {
                exportGroup.setType(ExportGroupType.Initiator.name());
                log.info("Reset export group type for export group (id={})", exportGroupId);
                exportGroups.add(exportGroup);
            }
        }
        dbClient.persistObject(exportGroups);
    }
}


while (exportGroupsIter.hasNext()) {
            ExportGroup exportGroup = exportGroupsIter.next();
            String exportGroupId = exportGroup.getId().toString();
            log.info("Examining ExportGroup (id={}) for upgrade", exportGroupId);
            String type = exportGroup.getType();
            if (type.equals(OLD_TYPE_VALUE)) {
                exportGroup.setType(ExportGroupType.Initiator.name());
                log.info("Reset export group type for export group (id={})", exportGroupId);
                exportGroups.add(exportGroup);
            }
        }
        dbClient.persistObject(exportGroups);
    }

/*
 * All Rights Reserved
 */
package com.emc.storageos.db.client.upgrade.callbacks;

import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.ExportGroup;
import com.emc.storageos.db.client.model.ExportGroup.ExportGroupType;
import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback;
import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException;

/**
 * Migration handler to convert value of type field for an export group, from
 * Exclusive to Initiator.
 */
public class ExportGroupTypeConverter extends BaseCustomMigrationCallback {

    private static final Logger log = LoggerFactory.getLogger(ExportGroupTypeConverter.class);

    private static final String TYPE_FIELD_NAME = "type";

    private static final String OLD_TYPE_VALUE = "Exclusive";

    @Override
    public void process() throws MigrationCallbackException {
        log.info("Handle ExportGroup type conversion");
        DbClient dbClient = getDbClient();
        List<URI> exportGroupURIs = dbClient.queryByType(ExportGroup.class, false);
        Iterator<ExportGroup> exportGroupsIter = dbClient.queryIterativeObjectField(ExportGroup.class, TYPE_FIELD_NAME, exportGroupURIs);
        List<ExportGroup> exportGroups = new ArrayList<ExportGroup>();


/*
 * All Rights Reserved
 */
package com.emc.storageos.db.client.upgrade.callbacks;

import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.ExportGroup;
import com.emc.storageos.db.client.model.ExportGroup.ExportGroupType;
import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback;
import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException;

/**
 * Migration handler to convert value of type field for an export group, from
 * Exclusive to Initiator.
 */
public class ExportGroupTypeConverter extends BaseCustomMigrationCallback {

    private static final Logger log = LoggerFactory.getLogger(ExportGroupTypeConverter.class);

    private static final String TYPE_FIELD_NAME = "type";

    private static final String OLD_TYPE_VALUE = "Exclusive";

    @Override
    public void process() throws MigrationCallbackException {
        log.info("Handle ExportGroup type conversion");
        DbClient dbClient = getDbClient();
        List<URI> exportGroupURIs = dbClient.queryByType(ExportGroup.class, false);
        Iterator<ExportGroup> exportGroupsIter = dbClient.queryIterativeObjectField(ExportGroup.class, TYPE_FIELD_NAME, exportGroupURIs);
        List<ExportGroup> exportGroups = new ArrayList<ExportGroup>();
        while (exportGroupsIter.hasNext()) {
            ExportGroup exportGroup = exportGroupsIter.next();
            String exportGroupId = exportGroup.getId().toString();
            log.info("Examining ExportGroup (id={}) for upgrade", exportGroupId);
            String type = exportGroup.getType();
            if (type.equals(OLD_TYPE_VALUE)) {
                exportGroup.setType(ExportGroupType.Initiator.name());
                log.info("Reset export group type for export group (id={})", exportGroupId);
                exportGroups.add(exportGroup);
            }
        }
        dbClient.persist


if (type.equals(OLD_TYPE_VALUE)) {
                exportGroup.setType(ExportGroupType.Initiator.name());
                log.info("Reset export group type for export group (id={})", exportGroupId);
                exportGroups.add(exportGroup);
            }

/*
 * All Rights Reserved
 */
package com.emc.storageos.db.client.upgrade.callbacks;

import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.ExportGroup;
import com.emc.storageos.db.client.model.ExportGroup.ExportGroupType;
import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback;
import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException;

/**
 * Migration handler to convert value of type field for an export group, from
 * Exclusive to Initiator.
 */
public class ExportGroupTypeConverter extends BaseCustomMigrationCallback {

    private static final Logger log = LoggerFactory.getLogger(ExportGroupTypeConverter.class);

    private static final String TYPE_FIELD_NAME = "type";

    private static final String OLD_TYPE_VALUE = "Exclusive";

    @Override
    public void process() throws MigrationCallbackException {
        log.info("Handle ExportGroup type conversion");
        DbClient dbClient = getDbClient();
        List<URI> exportGroupURIs = dbClient.queryByType(ExportGroup.class, false);
        Iterator<ExportGroup> exportGroupsIter = dbClient.queryIterativeObjectField(ExportGroup.class, TYPE_FIELD_NAME, exportGroupURIs);
        List<ExportGroup> exportGroups = new ArrayList<ExportGroup>();
        while (exportGroupsIter.hasNext()) {
            ExportGroup exportGroup = exportGroupsIter.next();
            String exportGroupId = exportGroup.getId().toString();
            log.info("Examining ExportGroup (id={}) for upgrade", exportGroupId);
            String type = exportGroup.getType();

        }
        dbClient.persistObject(exportGroups);
    }
}


/*
 * All Rights Reserved
 */
package com.emc.storageos.db.client.upgrade.callbacks;

import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.ExportGroup;
import com.emc.storageos.db.client.model.ExportGroup.ExportGroupType;
import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback;
import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException;

/**
 * Migration handler to convert value of type field for an export group, from
 * Exclusive to Initiator.
 */
public class ExportGroupTypeConverter extends BaseCustomMigrationCallback {

    private static final Logger log = LoggerFactory.getLogger(ExportGroupTypeConverter.class);

    private static final String TYPE_FIELD_NAME = "type";

    private static final String OLD_TYPE_VALUE = "Exclusive";

    @Override
    public void process() throws MigrationCallbackException {
        log.info("Handle ExportGroup type conversion");
        DbClient dbClient = getDbClient();
        List

<URI> exportGroupURIs = dbClient.queryByType(ExportGroup.class, false);
        Iterator<ExportGroup> exportGroupsIter = dbClient.queryIterativeObjectField(ExportGroup.class, TYPE_FIELD_NAME, exportGroupURIs);
        List<ExportGroup> exportGroups = new ArrayList<ExportGroup>();
        while (exportGroupsIter.hasNext()) {
            ExportGroup exportGroup = exportGroupsIter.next();
            String exportGroupId = exportGroup.getId().toString();
            log.info("Examining ExportGroup (id={}) for upgrade", exportGroupId);
            String type = exportGroup.getType();
            if (type.equals(OLD_TYPE_VALUE)) {
                exportGroup.setType(ExportGroupType.Initiator.name());
                log.info("Reset export group type for export group (id={})", exportGroupId);
                exportGroups.add(exportGroup);
            }
        }
        dbClient.persistObject(exportGroups);
    }
}


/**
 * **************************************************
 *
 *  AnchorableImageView.java
 *
 *  All rights reserved.
 *
 *  This view displays an image anchored to its top.
 *
 * ***************************************************
 */
package ly.kite.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;

public class AnchorableImageView extends ImageView {

    @SuppressWarnings("unused")
    private static final String LOG_TAG = "AnchorableImageView";

    private int mAnchorGravity;

    private float mAnchorPoint;

    private boolean mAnchored;

    private int mLeft;

    private int mTop;

    private int mRight;

    private int mBottom;

    public AnchorableImageView(Context context) {
        super(context);
    }

    public AnchorableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AnchorableImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * **************************************************
     *
     *  Sets the drawable.
     *
     * ***************************************************
     */
    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
    }

    /**
     * **************************************************
     *
     *  Called when the size changes.
     *
     * ***************************************************
     */
    @Override
    public void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        if (mAnchored)
            calculateDrawableBounds(width, height);
    }

    /**
     * **************************************************
     *
     *  Draws the image view.
     *
     * ***************************************************
     */
    @Override
    public void onDraw(Canvas canvas) {
        if (mAnchored) {
            // Get the image
            Drawable drawable = getDrawable();
            if (drawable == null)
                return;
            // Draw the image onto the canvas
            drawable.setBounds(mLeft, mTop, mRight, mBottom);
            drawable.draw(canvas);
        } else {
            super.onDraw(canvas);
        }
    }

    /**
     * **************************************************
     *
     *  Sets the anchor gravity.
     *
     * ***************************************************
     */
    public void setAnchorGravity(int gravity) {
        mAnchorGravity = gravity;
        if (gravity == Gravity.LEFT || gravity == Gravity.TOP || gravity == Gravity.RIGHT || gravity == Gravity.BOTTOM) {
            mAnchored = true;
            calculateDrawableBounds(getWidth(), getHeight());
        } else {
            mAnchored = false;
        }
        invalidate();
    }

    /**
     * **************************************************
     *
     *  Sets the anchor point. This is the point on the image
     *  (as a proportion of the image size) that is fixed to
     *  the anchor position (defined by the gravity).
     *
     *  Has no effect if the anchor gravity is not set.
     *
     * ***************************************************
     */

{
        mAnchorPoint = point;
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
        invalidate();
    }

    /**
     * **************************************************
     *
     *  Calculates the drawable bounds.
     *
     *  TODO: Factor in the anchor point
     *
     * ***************************************************
     */
    private void calculateDrawableBounds(int viewWidth, int viewHeight) {
        // Make sure we have all the details we need
        if (viewWidth < 1 || viewHeight < 1)
            return;
        Drawable drawable = getDrawable();
        if (drawable == null)
            return;
        int drawableWidth = drawable.getIntrinsicWidth();
        int drawableHeight = drawable.getIntrinsicHeight();
        if (drawableWidth < 1 || drawableHeight < 1)
            return;
        int viewHalfWidth = (int) (viewWidth * 0.5f);
        int viewHalfHeight = (int) (viewHeight * 0.5f);
        // Since we are being anchored, we have the option of filling the entire view, or
        // fitting inside it. Work out which from the scale type.
        ScaleType scaleType = getScaleType();
        boolean fillView = (scaleType == ScaleType.CENTER_CROP || scaleType == ScaleType.CENTER.FIT_END || scaleType == ScaleType.FIT_XY);
        // Calculate the scale factor according to whether we're filling the view or not
        float widthScaleFactor = (float) viewWidth / (float) drawableWidth;
        float heightScaleFactor = (float) viewHeight / (float) drawableHeight;
        float scaleFactor;
        if (fillView) {
            scaleFactor = Math.max(widthScaleFactor, heightScaleFactor);
        } else {
            scaleFactor = Math.min(widthScaleFactor, heightScaleFactor);
        }
        int scaledDrawableWidth = (int) (drawableWidth * scaleFactor);
        int scaledDrawableHeight = (int) (drawableHeight * scaleFactor);
        int scaledDrawableHalfWidth = (int) (scaledDrawableWidth * 0.5f);
        int scaledDrawableHalfHeight = (int) (scaledDrawableHeight * 0.5f);
        // Once we've determined what the anchor gravity is, calculate the bounds
        // of the image to match.
        if (mAnchorGravity == Gravity.LEFT) {
            mLeft = 0;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = scaledDrawableWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.TOP) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = 0;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = scaledDrawableHeight;
        } else if (mAnchorGravity == Gravity.RIGHT) {
            mLeft = viewWidth - scaledDrawableWidth;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = viewWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.BOTTOM) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = viewHeight - scaledDrawableHeight;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = viewHeight;
        }
    }
}


{
        mAnchorPoint = point;
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
        invalidate();
    }

/**
 * **************************************************
 *
 *  AnchorableImageView.java
 *
 *  All rights reserved.
 *
 *  This view displays an image anchored to its top.
 *
 * ***************************************************
 */
package ly.kite.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;

public class AnchorableImageView extends ImageView {

    @SuppressWarnings("unused")
    private static final String LOG_TAG = "AnchorableImageView";

    private int mAnchorGravity;

    private float mAnchorPoint;

    private boolean mAnchored;

    private int mLeft;

    private int mTop;

    private int mRight;

    private int mBottom;

    public AnchorableImageView(Context context) {
        super(context);
    }

    public AnchorableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AnchorableImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * **************************************************
     *
     *  Sets the drawable.
     *
     * ***************************************************
     */
    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
    }

    /**
     * **************************************************
     *
     *  Called when the size changes.
     *
     * ***************************************************
     */
    @Override
    public void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        if (mAnchored)
            calculateDrawableBounds(width, height);
    }

    /**
     * **************************************************
     *
     *  Draws the image view.
     *
     * ***************************************************
     */
    @Override
    public void onDraw(Canvas canvas) {
        if (mAnchored) {
            // Get the image
            Drawable drawable = getDrawable();
            if (drawable == null)
                return;
            // Draw the image onto the canvas
            drawable.setBounds(mLeft, mTop, mRight, mBottom);
            drawable.draw(canvas);
        } else {
            super.onDraw(canvas);
        }
    }

    /**
     * **************************************************
     *
     *  Sets the anchor gravity.
     *
     * ***************************************************
     */
    public void setAnchorGravity(int gravity) {
        mAnchorGravity = gravity;
        if (gravity == Gravity.LEFT || gravity == Gravity.TOP || gravity == Gravity.RIGHT || gravity == Gravity.BOTTOM) {
            mAnchored = true;
            calculateDrawableBounds(getWidth(), getHeight());
        } else {
            mAnchored = false;
        }
        invalidate();
    }

    /**
     * **************************************************
     *
     *  Sets the anchor point. This is the point on the image
     *  (as a proportion of the image size) that is fixed to
     *  the anchor position (defined by the gravity).
     *
     *  Has no effect if the anchor gravity is not set.
     *
     * ***************************************************
     */
    public void setAnchorPoint(float point)

    /**
     * **************************************************
     *
     *  Calculates the drawable bounds.
     *
     *  TODO: Factor in the anchor point
     *
     * ***************************************************
     */
    private void calculateDrawableBounds(int viewWidth, int viewHeight) {
        // Make sure we have all the details we need
        if (viewWidth < 1 || viewHeight < 1)
            return;
        Drawable drawable = getDrawable();
        if (drawable == null)
            return;
        int drawableWidth = drawable.getIntrinsicWidth();
        int drawableHeight = drawable.getIntrinsicHeight();
        if (drawableWidth < 1 || drawableHeight < 1)
            return;
        int viewHalfWidth = (int) (viewWidth * 0.5f);
        int viewHalfHeight = (int) (viewHeight * 0.5f);
        // Since we are being anchored, we have the option of filling the entire view, or
        // fitting inside it. Work out which from the scale type.
        ScaleType scaleType = getScaleType();
        boolean fillView = (scaleType == ScaleType.CENTER_CROP || scaleType == ScaleType.CENTER.FIT_END || scaleType == ScaleType.FIT_XY);
        // Calculate the scale factor according to whether we're filling the view or not
        float widthScaleFactor = (float) viewWidth / (float) drawableWidth;
        float heightScaleFactor = (float) viewHeight / (float) drawableHeight;
        float scaleFactor;
        if (fillView) {
            scaleFactor = Math.max(widthScaleFactor, heightScaleFactor);
        } else {
            scaleFactor = Math.min(widthScaleFactor, heightScaleFactor);
        }
        int scaledDrawableWidth = (int) (drawableWidth * scaleFactor);
        int scaledDrawableHeight = (int) (drawableHeight * scaleFactor);
        int scaledDrawableHalfWidth = (int) (scaledDrawableWidth * 0.5f);
        int scaledDrawableHalfHeight = (int) (scaledDrawableHeight * 0.5f);
        // Once we've determined what the anchor gravity is, calculate the bounds
        // of the image to match.
        if (mAnchorGravity == Gravity.LEFT) {
            mLeft = 0;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = scaledDrawableWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.TOP) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = 0;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = scaledDrawableHeight;
        } else if (mAnchorGravity == Gravity.RIGHT) {
            mLeft = viewWidth - scaledDrawableWidth;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = viewWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.BOTTOM) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = viewHeight - scaledDrawableHeight;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = viewHeight;
        }
    }
}


/**
 * **************************************************
 *
 *  AnchorableImageView.java
 *
 *  All rights reserved.
 *
 *  This view displays an image anchored to its top.
 *
 * ***************************************************
 */
package ly.kite.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;

public class AnchorableImageView extends ImageView {

    @SuppressWarnings("unused")
    private static final String LOG_TAG = "AnchorableImageView";

    private int mAnchorGravity;

    private float mAnchorPoint;

    private boolean mAnchored;

    private int mLeft;

    private int mTop;

    private int mRight;

    private int mBottom;

    public AnchorableImageView(Context context) {
        super(context);
    }

    public AnchorableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AnchorableImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * **************************************************
     *
     *  Sets the drawable.
     *
     * ***************************************************
     */
    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
    }

    /**
     * **************************************************
     *
     *  Called when the size changes.
     *
     * ***************************************************
     */
    @Override
    public void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        if (mAnchored)
            calculateDrawableBounds(width, height);
    }

    /**
     * **************************************************
     *
     *  Draws the image view.
     *
     * ***************************************************
     */
    @Override
    public void onDraw(Canvas canvas) {
        if (mAnchored) {
            // Get the image
            Drawable drawable = getDrawable();
            if (drawable == null)
                return;
            // Draw the image onto the canvas
            drawable.setBounds(mLeft, mTop, mRight, mBottom);
            drawable.draw(canvas);
        } else {
            super.onDraw(canvas);
        }
    }

    /**
     * **************************************************
     *
     *  Sets the anchor gravity.
     *
     * ***************************************************
     */
    public void setAnchorGravity(int gravity) {

        if (gravity == Gravity.LEFT || gravity == Gravity.TOP || gravity == Gravity.RIGHT || gravity == Gravity.BOTTOM) {
            mAnchored = true;
            calculateDrawableBounds(getWidth(), getHeight());
        } else {
            mAnchored = false;
        }
        invalidate();
    }

    /**
     * **************************************************
     *
     *  Sets the anchor point. This is the point on the image
     *  (as a proportion of the image size) that is fixed to
     *  the anchor position (defined by the gravity).
     *
     *  Has no effect if the anchor gravity is not set.
     *
     * ***************************************************
     */
    public void setAnchorPoint(float point) {
        mAnchorPoint = point;
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
        invalidate();
    }

    /**
     * **************************************************
     *
     *  Calculates the drawable bounds.
     *
     *  TODO: Factor in the anchor point
     *
     * ***************************************************
     */
    private void calculateDrawableBounds(int viewWidth, int viewHeight) {
        // Make sure we have all the details we need
        if (viewWidth < 1 || viewHeight < 1)
            return;
        Drawable drawable = getDrawable();
        if (drawable == null)
            return;
        int drawableWidth = drawable.getIntrinsicWidth();
        int drawableHeight = drawable.getIntrinsicHeight();
        if (drawableWidth < 1 || drawableHeight < 1)
            return;
        int viewHalfWidth = (int) (viewWidth * 0.5f);
        int viewHalfHeight = (int) (viewHeight * 0.5f);
        // Since we are being anchored, we have the option of filling the entire view, or
        // fitting inside it. Work out which from the scale type.
        ScaleType scaleType = getScaleType();
        boolean fillView = (scaleType == ScaleType.CENTER_CROP || scaleType == ScaleType.CENTER.FIT_END || scaleType == ScaleType.FIT_XY);
        // Calculate the scale factor according to whether we're filling the view or not
        float widthScaleFactor = (float) viewWidth / (float) drawableWidth;
        float heightScaleFactor = (float) viewHeight / (float) drawableHeight;
        float scaleFactor;
        if (fillView) {
            scaleFactor = Math.max(widthScaleFactor, heightScaleFactor);
        } else {
            scaleFactor = Math.min(widthScaleFactor, heightScaleFactor);
        }
        int scaledDrawableWidth = (int) (drawableWidth * scaleFactor);
        int scaledDrawableHeight = (int) (drawableHeight * scaleFactor);
        int scaledDrawableHalfWidth = (int) (scaledDrawableWidth * 0.5f);
        int scaledDrawableHalfHeight = (int) (scaledDrawableHeight * 0.5f);
        // Once we've determined what the anchor gravity is, calculate the bounds
        // of the image to match.
        if (mAnchorGravity == Gravity.LEFT) {
            mLeft = 0;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = scaledDrawableWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.TOP) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = 0;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = scaledDrawableHeight;
        } else if (mAnchorGravity == Gravity.RIGHT) {
            mLeft = viewWidth - scaledDrawableWidth;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = viewWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.BOTTOM) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = viewHeight - scaledDrawableHeight;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = viewHeight;
        }
    }
}


if (gravity == Gravity.LEFT || gravity == Gravity.TOP || gravity == Gravity.RIGHT || gravity == Gravity.BOTTOM) {
            mAnchored = true;
            calculateDrawableBounds(getWidth(), getHeight());
        } else {
            mAnchored = false;
        }

/**
 * **************************************************
 *
 *  AnchorableImageView.java
 *
 *  All rights reserved.
 *
 *  This view displays an image anchored to its top.
 *
 * ***************************************************
 */
package ly.kite.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;

public class AnchorableImageView extends ImageView {

    @SuppressWarnings("unused")
    private static final String LOG_TAG = "AnchorableImageView";

    private int mAnchorGravity;

    private float mAnchorPoint;

    private boolean mAnchored;

    private int mLeft;

    private int mTop;

    private int mRight;

    private int mBottom;

    public AnchorableImageView(Context context) {
        super(context);
    }

    public AnchorableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AnchorableImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * **************************************************
     *
     *  Sets the drawable.
     *
     * ***************************************************
     */
    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
    }

    /**
     * **************************************************
     *
     *  Called when the size changes.
     *
     * ***************************************************
     */
    @Override
    public void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        if (mAnchored)
            calculateDrawableBounds(width, height);
    }

    /**
     * **************************************************
     *
     *  Draws the image view.
     *
     * ***************************************************
     */
    @Override
    public void onDraw(Canvas canvas) {
        if (mAnchored) {
            // Get the image
            Drawable drawable = getDrawable();
            if (drawable == null)
                return;
            // Draw the image onto the canvas
            drawable.setBounds(mLeft, mTop, mRight, mBottom);
            drawable.draw(canvas);
        } else {
            super.onDraw(canvas);
        }
    }

    /**
     * **************************************************
     *
     *  Sets the anchor gravity.
     *
     * ***************************************************
     */
    public void setAnchorGravity(int gravity) {
        mAnchorGravity = gravity;

        invalidate();
    }

    /**
     * **************************************************
     *
     *  Sets the anchor point. This is the point on the image
     *  (as a proportion of the image size) that is fixed to
     *  the anchor position (defined by the gravity).
     *
     *  Has no effect if the anchor gravity is not set.
     *
     * ***************************************************
     */
    public void setAnchorPoint(float point) {
        mAnchorPoint = point;
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
        invalidate();
    }

    /**
     * **************************************************
     *
     *  Calculates the drawable bounds.
     *
     *  TODO: Factor in the anchor point
     *
     * ***************************************************
     */
    private void calculateDrawableBounds(int viewWidth, int viewHeight) {
        // Make sure we have all the details we need
        if (viewWidth < 1 || viewHeight < 1)
            return;
        Drawable drawable = getDrawable();
        if (drawable == null)
            return;
        int drawableWidth = drawable.getIntrinsicWidth();
        int drawableHeight = drawable.getIntrinsicHeight();
        if (drawableWidth < 1 || drawableHeight < 1)
            return;
        int viewHalfWidth = (int) (viewWidth * 0.5f);
        int viewHalfHeight = (int) (viewHeight * 0.5f);
        // Since we are being anchored, we have the option of filling the entire view, or
        // fitting inside it. Work out which from the scale type.
        ScaleType scaleType = getScaleType();
        boolean fillView = (scaleType == ScaleType.CENTER_CROP || scaleType == ScaleType.CENTER.FIT_END || scaleType == ScaleType.FIT_XY);
        // Calculate the scale factor according to whether we're filling the view or not
        float widthScaleFactor = (float) viewWidth / (float) drawableWidth;
        float heightScaleFactor = (float) viewHeight / (float) drawableHeight;
        float scaleFactor;
        if (fillView) {
            scaleFactor = Math.max(widthScaleFactor, heightScaleFactor);
        } else {
            scaleFactor = Math.min(widthScaleFactor, heightScaleFactor);
        }
        int scaledDrawableWidth = (int) (drawableWidth * scaleFactor);
        int scaledDrawableHeight = (int) (drawableHeight * scaleFactor);
        int scaledDrawableHalfWidth = (int) (scaledDrawableWidth * 0.5f);
        int scaledDrawableHalfHeight = (int) (scaledDrawableHeight * 0.5f);
        // Once we've determined what the anchor gravity is, calculate the bounds
        // of the image to match.
        if (mAnchorGravity == Gravity.LEFT) {
            mLeft = 0;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = scaledDrawableWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.TOP) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = 0;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = scaledDrawableHeight;
        } else if (mAnchorGravity == Gravity.RIGHT) {
            mLeft = viewWidth - scaledDrawableWidth;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = viewWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.BOTTOM) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = viewHeight - scaledDrawableHeight;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = viewHeight;
        }
    }
}


/**
 * **************************************************
 *
 *  AnchorableImageView.java
 *
 *  All rights reserved.
 *
 *  This view displays an image anchored to its top.
 *
 * ***************************************************
 */
package ly.kite.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;

public class AnchorableImageView extends ImageView {

    @SuppressWarnings("unused")
    private static final String LOG_TAG = "AnchorableImageView";

    private int mAnchorGravity;

    private float mAnchorPoint;

    private boolean mAnchored;

    private int mLeft;

    private int mTop;

    private int mRight;

    private int mBottom;

    public AnchorableImageView(Context context) {
        super(context);
    }

    public AnchorableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AnchorableImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * **************************************************
     *
     *  Sets the drawable.
     *
     * ***************************************************
     */
    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
    }

    /**
     * **************************************************
     *
     *  Called when the size changes.
     *
     * ***************************************************
     */
    @Override
    public void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        if (mAnchored)
            calculateDrawableBounds(width, height);
    }

    /**
     * **************************************************
     *
     *  Draws the image view.
     *
     * ***************************************************
     */
    @Override
    public void onDraw(Canvas canvas) {
        if (mAnchored) {
            // Get the image
            Drawable drawable = getDrawable();
            if (drawable == null)
                return;
            // Draw the image onto the canvas
            drawable.setBounds(mLeft, mTop, mRight, mBottom);
            drawable.draw(canvas);
        } else {
            super.onDraw(canvas);
        }
    }

    /**
     * **************************************************
     *
     *  Sets the anchor gravity.
     *
     * ***************************************************
     */
    public void setAnchorGravity(int gravity) {
        mAnchorGravity = gravity;
        if (gravity == Gravity.LEFT || gravity == Gravity.TOP || gravity == Gravity.RIGHT || gravity == Gravity.BOTTOM) {
            mAnchored = true;
            calculateDrawableBounds(getWidth(), getHeight());
        } else {
            mAnchored = false;
        }

    /**
     * **************************************************
     *
     *  Sets the anchor point. This is the point on the image
     *  (as a proportion of the image size) that is fixed to
     *  the anchor position (defined by the gravity).
     *
     *  Has no effect if the anchor gravity is not set.
     *
     * ***************************************************
     */
    public void setAnchorPoint(float point) {
        mAnchorPoint = point;
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
        invalidate();
    }

    /**
     * **************************************************
     *
     *  Calculates the drawable bounds.
     *
     *  TODO: Factor in the anchor point
     *
     * ***************************************************
     */
    private void calculateDrawableBounds(int viewWidth, int viewHeight) {
        // Make sure we have all the details we need
        if (viewWidth < 1 || viewHeight < 1)
            return;
        Drawable drawable = getDrawable();
        if (drawable == null)
            return;
        int drawableWidth = drawable.getIntrinsicWidth();
        int drawableHeight = drawable.getIntrinsicHeight();
        if (drawableWidth < 1 || drawableHeight < 1)
            return;
        int viewHalfWidth = (int) (viewWidth * 0.5f);
        int viewHalfHeight = (int) (viewHeight * 0.5f);
        // Since we are being anchored, we have the option of filling the entire view, or
        // fitting inside it. Work out which from the scale type.
        ScaleType scaleType = getScaleType();
        boolean fillView = (scaleType == ScaleType.CENTER_CROP || scaleType == ScaleType.CENTER.FIT_END || scaleType == ScaleType.FIT_XY);
        // Calculate the scale factor according to whether we're filling the view or not
        float widthScaleFactor = (float) viewWidth / (float) drawableWidth;
        float heightScaleFactor = (float) viewHeight / (float) drawableHeight;
        float scaleFactor;
        if (fillView) {
            scaleFactor = Math.max(widthScaleFactor, heightScaleFactor);
        } else {
            scaleFactor = Math.min(widthScaleFactor, heightScaleFactor);
        }
        int scaledDrawableWidth = (int) (drawableWidth * scaleFactor);
        int scaledDrawableHeight = (int) (drawableHeight * scaleFactor);
        int scaledDrawableHalfWidth = (int) (scaledDrawableWidth * 0.5f);
        int scaledDrawableHalfHeight = (int) (scaledDrawableHeight * 0.5f);
        // Once we've determined what the anchor gravity is, calculate the bounds
        // of the image to match.
        if (mAnchorGravity == Gravity.LEFT) {
            mLeft = 0;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = scaledDrawableWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.TOP) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = 0;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = scaledDrawableHeight;
        } else if (mAnchorGravity == Gravity.RIGHT) {
            mLeft = viewWidth - scaledDrawableWidth;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = viewWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.BOTTOM) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = viewHeight - scaledDrawableHeight;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = viewHeight;
        }
    }
}


/**
 * **************************************************
 *
 *  AnchorableImageView.java
 *
 *  All rights reserved.
 *
 *  This view displays an image anchored to its top.
 *
 * ***************************************************
 */
package ly.kite.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;

public class AnchorableImageView extends ImageView {

    @SuppressWarnings("unused")
    private static final String LOG_TAG = "AnchorableImageView";

    private int mAnchorGravity;

    private float mAnchorPoint;

    private boolean mAnchored;

    private int mLeft;

    private int mTop;

    private int mRight;

    private int mBottom;

    public AnchorableImageView(Context context) {
        super(context);
    }

    public AnchorableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AnchorableImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * **************************************************
     *
     *  Sets the drawable.
     *
     * ***************************************************
     */
    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
    }

    /**
     * **************************************************
     *
     *  Called when the size changes.
     *
     * ***************************************************
     */
    @Override
    public void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        if (mAnchored)
            calculateDrawableBounds(width, height);
    }

    /**
     * **************************************************
     *
     *  Draws the image view.
     *
     * ***************************************************
     */
    @Override
    public void onDraw(Canvas canvas) {
        if (mAnchored) {
            // Get the image
            Drawable drawable = getDrawable();
            if (drawable == null)
                return;
            // Draw the image onto the canvas
            drawable.setBounds(mLeft, mTop, mRight, mBottom);
            drawable.draw(canvas);
        } else {
            super.onDraw(canvas);
        }
    }

    /**
     * **************************************************
     *
     *  Sets the anchor gravity.
     *
     * ***************************************************
     */
    public void setAnchorGravity(int gravity) {
        mAnchorGravity = gravity;
        if (gravity == Gravity.LEFT || gravity == Gravity.TOP || gravity == Gravity.RIGHT || gravity == Gravity.BOTTOM) {
            mAnchored = true;
            calculateDrawableBounds(getWidth(), getHeight());
        } else {
            mAnchored = false;
        }
        invalidate();
    }

    /**
     * **************************************************
     *
     *  Sets the anchor point. This is the point on the image
     *  (as a proportion of the image size) that is fixed to
     *  the anchor position (defined by the gravity).
     *
     *  Has no effect if the anchor gravity is not set.
     *
     * ***************************************************
     */
    public void setAnchorPoint(float point) {
        mAnchorPoint = point;
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
        invalidate();
    }

    /**
     * **************************************************
     *
     *  Calculates the drawable bounds.
     *
     *  TODO: Factor in the anchor point
     *
     * ***************************************************
     */
    private void calculateDrawableBounds(int viewWidth, int viewHeight) {
        // Make sure we have all the details we need
        if (viewWidth < 1 || viewHeight < 1)
            return;
        Drawable drawable = getDrawable();
        if (drawable == null)
            return;
        int drawableWidth = drawable.

        int drawableHeight = drawable.getIntrinsicHeight();
        if (drawableWidth < 1 || drawableHeight < 1)
            return;
        int viewHalfWidth = (int) (viewWidth * 0.5f);
        int viewHalfHeight = (int) (viewHeight * 0.5f);
        // Since we are being anchored, we have the option of filling the entire view, or
        // fitting inside it. Work out which from the scale type.
        ScaleType scaleType = getScaleType();
        boolean fillView = (scaleType == ScaleType.CENTER_CROP || scaleType == ScaleType.CENTER.FIT_END || scaleType == ScaleType.FIT_XY);
        // Calculate the scale factor according to whether we're filling the view or not
        float widthScaleFactor = (float) viewWidth / (float) drawableWidth;
        float heightScaleFactor = (float) viewHeight / (float) drawableHeight;
        float scaleFactor;
        if (fillView) {
            scaleFactor = Math.max(widthScaleFactor, heightScaleFactor);
        } else {
            scaleFactor = Math.min(widthScaleFactor, heightScaleFactor);
        }
        int scaledDrawableWidth = (int) (drawableWidth * scaleFactor);
        int scaledDrawableHeight = (int) (drawableHeight * scaleFactor);
        int scaledDrawableHalfWidth = (int) (scaledDrawableWidth * 0.5f);
        int scaledDrawableHalfHeight = (int) (scaledDrawableHeight * 0.5f);
        // Once we've determined what the anchor gravity is, calculate the bounds
        // of the image to match.
        if (mAnchorGravity == Gravity.LEFT) {
            mLeft = 0;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = scaledDrawableWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.TOP) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = 0;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = scaledDrawableHeight;
        } else if (mAnchorGravity == Gravity.RIGHT) {
            mLeft = viewWidth - scaledDrawableWidth;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = viewWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.BOTTOM) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = viewHeight - scaledDrawableHeight;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = viewHeight;
        }
    }
}


public void setAnchorGravity(int gravity) {
        mAnchorGravity = gravity;
        if (gravity == Gravity.LEFT || gravity == Gravity.TOP || gravity == Gravity.RIGHT || gravity == Gravity.BOTTOM) {
            mAnchored = true;
            calculateDrawableBounds(getWidth(), getHeight());
        } else {
            mAnchored = false;
        }
        invalidate();
    }

/**
 * **************************************************
 *
 *  AnchorableImageView.java
 *
 *  All rights reserved.
 *
 *  This view displays an image anchored to its top.
 *
 * ***************************************************
 */
package ly.kite.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;

public class AnchorableImageView extends ImageView {

    @SuppressWarnings("unused")
    private static final String LOG_TAG = "AnchorableImageView";

    private int mAnchorGravity;

    private float mAnchorPoint;

    private boolean mAnchored;

    private int mLeft;

    private int mTop;

    private int mRight;

    private int mBottom;

    public AnchorableImageView(Context context) {
        super(context);
    }

    public AnchorableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AnchorableImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * **************************************************
     *
     *  Sets the drawable.
     *
     * ***************************************************
     */
    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
    }

    /**
     * **************************************************
     *
     *  Called when the size changes.
     *
     * ***************************************************
     */
    @Override
    public void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        if (mAnchored)
            calculateDrawableBounds(width, height);
    }

    /**
     * **************************************************
     *
     *  Draws the image view.
     *
     * ***************************************************
     */
    @Override
    public void onDraw(Canvas canvas) {
        if (mAnchored) {
            // Get the image
            Drawable drawable = getDrawable();
            if (drawable == null)
                return;
            // Draw the image onto the canvas
            drawable.setBounds(mLeft, mTop, mRight, mBottom);
            drawable.draw(canvas);
        } else {
            super.onDraw(canvas);
        }
    }

    /**
     * **************************************************
     *
     *  Sets the anchor gravity.
     *
     * ***************************************************
     */


if (fillView) {
            scaleFactor = Math.max(widthScaleFactor, heightScaleFactor);
        } else {
            scaleFactor = Math.min(widthScaleFactor, heightScaleFactor);
        }

/**
 * **************************************************
 *
 *  AnchorableImageView.java
 *
 *  All rights reserved.
 *
 *  This view displays an image anchored to its top.
 *
 * ***************************************************
 */
package ly.kite.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;

public class AnchorableImageView extends ImageView {

    @SuppressWarnings("unused")
    private static final String LOG_TAG = "AnchorableImageView";

    private int mAnchorGravity;

    private float mAnchorPoint;

    private boolean mAnchored;

    private int mLeft;

    private int mTop;

    private int mRight;

    private int mBottom;

    public AnchorableImageView(Context context) {
        super(context);
    }

    public AnchorableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AnchorableImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * **************************************************
     *
     *  Sets the drawable.
     *
     * ***************************************************
     */
    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
    }

    /**
     * **************************************************
     *
     *  Called when the size changes.
     *
     * ***************************************************
     */
    @Override
    public void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        if (mAnchored)
            calculateDrawableBounds(width, height);
    }

    /**
     * **************************************************
     *
     *  Draws the image view.
     *
     * ***************************************************
     */
    @Override
    public void onDraw(Canvas canvas) {
        if (mAnchored) {
            // Get the image
            Drawable drawable = getDrawable();
            if (drawable == null)
                return;
            // Draw the image onto the canvas
            drawable.setBounds(mLeft, mTop, mRight, mBottom);
            drawable.draw(canvas);
        } else {
            super.onDraw(canvas);
        }
    }

    /**
     * **************************************************
     *
     *  Sets the anchor gravity.
     *
     * ***************************************************
     */
    public void setAnchorGravity(int gravity) {
        mAnchorGravity = gravity;
        if (gravity == Gravity.LEFT || gravity == Gravity.TOP || gravity == Gravity.RIGHT || gravity == Gravity.BOTTOM) {
            mAnchored = true;
            calculateDrawableBounds(getWidth(), getHeight());
        } else {
            mAnchored = false;
        }
        invalidate();
    }

    /**
     * **************************************************
     *
     *  Sets the anchor point. This is the point on the image
     *  (as a proportion of the image size) that is fixed to
     *  the anchor position (defined by the gravity).
     *
     *  Has no effect if the anchor gravity is not set.
     *
     * ***************************************************
     */
    public void setAnchorPoint(float point) {
        mAnchorPoint = point;
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
        invalidate();
    }

    /**
     * **************************************************
     *
     *  Calculates the drawable bounds.
     *
     *  TODO: Factor in the anchor point
     *
     * ***************************************************
     */
    private void calculateDrawableBounds(int viewWidth, int viewHeight) {
        // Make sure we have all the details we need
        if (viewWidth < 1 || viewHeight < 1)
            return;
        Drawable drawable = getDrawable();
        if (drawable == null)
            return;
        int drawableWidth = drawable.getIntrinsicWidth();
        int drawableHeight = drawable.getIntrinsicHeight();
        if (drawableWidth < 1 || drawableHeight < 1)
            return;
        int viewHalfWidth = (int) (viewWidth * 0.5f);
        int viewHalfHeight = (int) (viewHeight * 0.5f);
        // Since we are being anchored, we have the option of filling the entire view, or
        // fitting inside it. Work out which from the scale type.
        ScaleType scaleType = getScaleType();
        boolean fillView = (scaleType == ScaleType.CENTER_CROP || scaleType == ScaleType.CENTER.FIT_END || scaleType == ScaleType.FIT_XY);
        // Calculate the scale factor according to whether we're filling the view or not
        float widthScaleFactor = (float) viewWidth / (float) drawableWidth;
        float heightScaleFactor = (float) viewHeight / (float) drawableHeight;
        float scaleFactor;

        int scaledDrawableWidth = (int) (drawableWidth * scaleFactor);
        int scaledDrawableHeight = (int) (drawableHeight * scaleFactor);
        int scaledDrawableHalfWidth = (int) (scaledDrawableWidth * 0.5f);
        int scaledDrawableHalfHeight = (int) (scaledDrawableHeight * 0.5f);
        // Once we've determined what the anchor gravity is, calculate the bounds
        // of the image to match.
        if (mAnchorGravity == Gravity.LEFT) {
            mLeft = 0;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = scaledDrawableWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.TOP) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = 0;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = scaledDrawableHeight;
        } else if (mAnchorGravity == Gravity.RIGHT) {
            mLeft = viewWidth - scaledDrawableWidth;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = viewWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.BOTTOM) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = viewHeight - scaledDrawableHeight;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = viewHeight;
        }
    }
}


/**
 * **************************************************
 *
 *  AnchorableImageView.java
 *
 *  All rights reserved.
 *
 *  This view displays an image anchored to its top.
 *
 * ***************************************************
 */
package ly.kite.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;

public class AnchorableImageView extends ImageView {

    @SuppressWarnings("unused")
    private static final String LOG_TAG = "AnchorableImageView";

    private int mAnchorGravity;

    private float mAnchorPoint;

    private boolean mAnchored;

    private int mLeft;

    private int mTop;

    private int mRight;

    private int mBottom;

    public AnchorableImageView(Context context) {
        super(context);
    }

    public AnchorableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AnchorableImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * **************************************************
     *
     *  Sets the drawable.
     *
     * ***************************************************
     */
    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
    }

    /**
     * ******

********************************************
     *
     *  Called when the size changes.
     *
     * ***************************************************
     */
    @Override
    public void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        if (mAnchored)
            calculateDrawableBounds(width, height);
    }

    /**
     * **************************************************
     *
     *  Draws the image view.
     *
     * ***************************************************
     */
    @Override
    public void onDraw(Canvas canvas) {
        if (mAnchored) {
            // Get the image
            Drawable drawable = getDrawable();
            if (drawable == null)
                return;
            // Draw the image onto the canvas
            drawable.setBounds(mLeft, mTop, mRight, mBottom);
            drawable.draw(canvas);
        } else {
            super.onDraw(canvas);
        }
    }

    /**
     * **************************************************
     *
     *  Sets the anchor gravity.
     *
     * ***************************************************
     */
    public void setAnchorGravity(int gravity) {
        mAnchorGravity = gravity;
        if (gravity == Gravity.LEFT || gravity == Gravity.TOP || gravity == Gravity.RIGHT || gravity == Gravity.BOTTOM) {
            mAnchored = true;
            calculateDrawableBounds(getWidth(), getHeight());
        } else {
            mAnchored = false;
        }
        invalidate();
    }

    /**
     * **************************************************
     *
     *  Sets the anchor point. This is the point on the image
     *  (as a proportion of the image size) that is fixed to
     *  the anchor position (defined by the gravity).
     *
     *  Has no effect if the anchor gravity is not set.
     *
     * ***************************************************
     */
    public void setAnchorPoint(float point) {
        mAnchorPoint = point;
        if (mAnchored)
            calculateDrawableBounds(getWidth(), getHeight());
        invalidate();
    }

    /**
     * **************************************************
     *
     *  Calculates the drawable bounds.
     *
     *  TODO: Factor in the anchor point
     *
     * ***************************************************
     */
    private void calculateDrawableBounds(int viewWidth, int viewHeight) {
        // Make sure we have all the details we need
        if (viewWidth < 1 || viewHeight < 1)
            return;
        Drawable drawable = getDrawable();
        if (drawable == null)
            return;
        int drawableWidth = drawable.getIntrinsicWidth();
        int drawableHeight = drawable.getIntrinsicHeight();
        if (drawableWidth < 1 || drawableHeight < 1)
            return;
        int viewHalfWidth = (int) (viewWidth * 0.5f);
        int viewHalfHeight = (int) (viewHeight * 0.5f);
        // Since we are being anchored, we have the option of filling the entire view, or
        // fitting inside it. Work out which from the scale type.
        ScaleType scaleType = getScaleType();
        boolean fillView = (scaleType == ScaleType.CENTER_CROP || scaleType == ScaleType.CENTER.FIT_END || scaleType == ScaleType.FIT_XY);
        // Calculate the scale factor according to whether we're filling the view or not
        float widthScaleFactor = (float) viewWidth / (float) drawableWidth;
        float heightScaleFactor = (float) viewHeight / (float) drawableHeight;
        float scaleFactor;
        if (fillView) {
            scaleFactor = Math.max(widthScaleFactor, heightScaleFactor);
        } else {
            scaleFactor = Math.min(widthScaleFactor, heightScaleFactor);
        }
        int scaledDrawableWidth = (int) (drawableWidth * scaleFactor);
        int scaledDrawableHeight = (int) (drawableHeight * scaleFactor);
        int scaledDrawableHalfWidth = (int) (scaledDrawableWidth * 0.5f);
        int scaledDrawableHalfHeight = (int) (scaledDrawableHeight * 0.5f);
        // Once we've determined what the anchor gravity is, calculate the bounds
        // of the image to match.
        if (mAnchorGravity == Gravity.LEFT) {
            mLeft = 0;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = scaledDrawableWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.TOP) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = 0;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = scaledDrawableHeight;
        } else if (mAnchorGravity == Gravity.RIGHT) {
            mLeft = viewWidth - scaledDrawableWidth;
            mTop = viewHalfHeight - scaledDrawableHalfHeight;
            mRight = viewWidth;
            mBottom = viewHalfHeight + scaledDrawableHalfHeight;
        } else if (mAnchorGravity == Gravity.BOTTOM) {
            mLeft = viewHalfWidth - scaledDrawableHalfWidth;
            mTop = viewHeight - scaledDrawableHeight;
            mRight = viewHalfWidth + scaledDrawableHalfWidth;
            mBottom = viewHeight;
        }
    }
}