DataModel.java

/**
* Copyright (c) 2012-2013 Nokia Corporation. All rights reserved.
* Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. 
* Oracle and Java are trademarks or registered trademarks of Oracle and/or its
* affiliates. Other product and company names mentioned herein may be trademarks
* or trade names of their respective owners. 
* See LICENSE.TXT for license information.
*/
package com.nokia.example.attractions;

import com.nokia.example.attractions.models.Attraction;
import com.nokia.example.attractions.models.Guide;
import com.nokia.maps.common.GeoCoordinate;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Vector;
import javax.microedition.rms.RecordEnumeration;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;

/**
 * Contains the data used in the application:
 * Guide and Attraction objects.
 * 
 * @see com.nokia.example.attractions.models.Attraction
 * @see com.nokia.example.attractions.models.Guide
 * 
 */
public final class DataModel {

    private static DataModel self = null;
    private Vector guides;
    private int currentGuideIndex = -1;  // selected guide
    private Vector attractions;
    private int currentAttractionIndex = -1;  // selected attraction
    private GeoCoordinate currentPosition = null;
    private int accuracy = 10;  // accuracy of the position in meters

    /**
     * @return DataModel singleton
     */
    public static DataModel getInstance() {
        if (self == null) {
            self = new DataModel();
        }
        return self;
    }

    public final void setAttractions(Vector attractions) {
        if (this.attractions == attractions) {
            return;
        }
        this.attractions = attractions;
        updateDistances();
    }

    public final Vector getGuides() {
        return guides;
    }

    public final Vector getAttractions() {
        return attractions;
    }

    public final void setCurrentGuideIndex(int index) {
        if (index != this.currentGuideIndex) {
            this.currentGuideIndex = index;
            setAttractions(null);
        }
    }

    public final int getCurrentGuideIndex() {
        return currentGuideIndex;
    }

    public final Guide getCurrentGuide() {
        return (Guide) guides.elementAt(currentGuideIndex);
    }

    public final void setCurrentAttractionIndex(int index) {
        this.currentAttractionIndex = index;
    }

    public final int getCurrentAttractionIndex() {
        return currentAttractionIndex;
    }

    public final Attraction getCurrentAttraction() {
        try {
            return (Attraction) attractions.elementAt(currentAttractionIndex);
        }
        catch (ArrayIndexOutOfBoundsException e) {
            return null;
        }
    }

    public final void setCurrentPosition(GeoCoordinate position, int accuracy) {
        this.currentPosition = position;
        this.accuracy = accuracy;
        updateDistances();
    }

    public final GeoCoordinate getCurrentPosition() {
        return currentPosition;
    }

    public final int getAccuracy() {
        return accuracy;
    }

    /**
     * Returns a string with the distance from the current position
     * to the given attraction.
     * @param attraction
     * @return 
     */
    private String distanceToAttraction(Attraction attraction) {
        final GeoCoordinate position = currentPosition;
        if (position == null) {
            return null;
        }
        double distance = position.distanceTo(attraction.getLocation());
        if (distance < 1000.0) {
            return ((int) (distance)) + " m";
        }
        else {
            String d = String.valueOf(distance % 1000).substring(0, 1);
            return (int) (distance / 1000) + "." + d + " km";
        }
    }

    /**
     * Iterates over the attractions and updates the distance to them.
     */
    private void updateDistances() {
        Vector attrs = attractions;
        if (attrs != null) {
            for (int i = 0; i < attrs.size(); i++) {
                Attraction a = (Attraction) attrs.elementAt(i);
                a.setDistance(distanceToAttraction(a));
            }
        }
    }

    /**
     * Save guides to RMS.
     */
    public final void saveGuides() {
        try {
            RecordStore store = RecordStore.openRecordStore("Guides", true);
            if (store.getNumRecords() == 0) {
                store.addRecord(null, 0, 0);
            }
            byte[] data = guidesState();
            store.setRecord(getRecordId(store), data, 0, data.length);
            store.closeRecordStore();
        }
        catch (Exception e) {
            try {
                RecordStore.deleteRecordStore("Guides");
            }
            catch (RecordStoreException rse) {
            }
        }
    }

    private int getRecordId(RecordStore store)
        throws RecordStoreException {
        RecordEnumeration e = store.enumerateRecords(null, null, false);
        try {
            return e.nextRecordId();
        }
        finally {
            e.destroy();
        }
    }

    private byte[] guidesState() {
        ByteArrayOutputStream bout = null;
        try {
            bout = new ByteArrayOutputStream();
            DataOutputStream dout = new DataOutputStream(bout);
            dout.writeInt(guides.size());
            for (int i = 0, size = guides.size(); i < size; i++) {
                ((Guide) guides.elementAt(i)).writeTo(dout);
            }
            dout.writeInt(currentGuideIndex);
            return bout.toByteArray();
        }
        catch (IOException e) {
        }
        finally {
            try {
                if (bout != null) {
                    bout.close();
                }
            }
            catch (IOException e) {
            }
        }
        return new byte[0];
    }

    /**
     * Load guides from RMS.
     */
    public final void loadGuides() {
        try {
            RecordStore store = RecordStore.openRecordStore("Guides", true);
            if (store.getNumRecords() == 0
                || !loadGuides(store.getRecord(getRecordId(store)))) {
                guides = new Vector();
            }
            store.closeRecordStore();
        }
        catch (RecordStoreException e) {
            guides = new Vector();
        }
    }

    private boolean loadGuides(byte[] record) {
        if (record == null) {
            return false;
        }
        try {
            DataInputStream din = new DataInputStream(new ByteArrayInputStream(
                record));
            guides = new Vector();
            int size = din.readInt();
            while (size > 0) {
                guides.addElement(Guide.readFrom(din));
                size--;
            }
            currentGuideIndex = din.readInt();
            return true;
        }
        catch (IOException e) {
        }
        return false;
    }
}