WeatherLayout.java

/*
 * Copyright © 2012 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.weatherapp.views;

import com.nokia.example.weatherapp.helpers.TextWrapper;
import com.nokia.example.weatherapp.helpers.UnitUtil;
import com.nokia.example.weatherapp.network.Weather;
import com.nokia.example.weatherapp.resources.Resources;
import com.nokia.example.weatherapp.resources.Settings;
import com.nokia.example.weatherapp.resources.Visual;
import java.util.Vector;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.Sprite;

/**
 * Paints the forecast data to weather view canvas
 */
public class WeatherLayout {

    public static void layout(Weather weather, Graphics g, Visual v, Resources r, WeatherView wv) {
        if (wv.getWidth() < 240) {
            layoutToTinyPortrait(weather, g, v, r, wv);
        }
        else if (wv.getWidth() <= wv.getHeight()) {
            layoutToPortrait(weather, g, v, r, wv);
        }
        else {
            layoutToLandscape(weather, g, v, r, wv);
        }
    }

    /**
     * Portrait flavor
     */
    public static void layoutToPortrait(Weather weather, Graphics g, Visual v, Resources r, WeatherView wv) {
        int headerHeight = v.HEIGHT_HEADER;
        int margin = (int) (0.06 * wv.getWidth());
        int width = wv.getWidth();
        int height = wv.getHeight();
        int anchorX = width / 2;
        int anchorY = headerHeight + height / 4;

        // Draw weather icon
        Image weatherIcon = getWeatherIcon(r, wv, weather.iconUrl);
        if (weatherIcon != null) {
            g.drawImage(weatherIcon, anchorX, anchorY, Graphics.VCENTER | Graphics.RIGHT);
        }

        // Draw temperature
        g.setColor(v.COLOR_PRIMARY_TEXT);
        g.setFont(v.FONT_LARGE);
        int fontHeight = g.getFont().getHeight();
        anchorY -= fontHeight - 10;
        anchorX = width / 20 * 11;
        if (wv.getDay() == 0) {
            if (Settings.temperatureUnit == Settings.CELSIUS) {
                g.drawString(weather.temperatureC + " °C", anchorX, anchorY, Graphics.BOTTOM | Graphics.LEFT);
            }
            else {
                g.drawString(weather.temperatureF + " °F", anchorX, anchorY, Graphics.BOTTOM | Graphics.LEFT);
            }
        }
        else {
            String maxTemp = weather.maxTempC + (Settings.temperatureUnit == Settings.CELSIUS ? " °C" : " °F");
            String minTemp = weather.minTempC + (Settings.temperatureUnit == Settings.CELSIUS ? " °C" : " °F");
            int offset = Math.max(g.getFont().stringWidth(maxTemp), g.getFont().stringWidth(minTemp));

            g.drawString(maxTemp, anchorX + offset, anchorY, Graphics.BOTTOM | Graphics.RIGHT);
            g.drawString(minTemp, anchorX + offset, anchorY + fontHeight, Graphics.BOTTOM | Graphics.RIGHT);

            g.setFont(v.FONT_SMALL);
            g.drawString(" max", anchorX + offset, anchorY, Graphics.BOTTOM | Graphics.LEFT);
            g.drawString(" min", anchorX + offset, anchorY + fontHeight, Graphics.BOTTOM | Graphics.LEFT);
            anchorY += fontHeight;
        }

        // Draw weather description
        g.setFont(v.FONT_SMALL);
        fontHeight = g.getFont().getHeight();
        Vector lines = TextWrapper.wrapTextToWidth(weather.description,
                                                   wv.getWidth() / 2 - 2 * margin, v.FONT_SMALL);
        int length = lines.size();
        for (int i = 0; i < length; i++) {
            String line = (String) lines.elementAt(i);
            g.drawString(line, anchorX, anchorY, Graphics.TOP | Graphics.LEFT);
            anchorY += fontHeight;
        }

        // Draw wind speed description
        try {
            lines = TextWrapper.wrapTextToWidth(UnitUtil.getBeaufortDesc(
                    Double.parseDouble(weather.windSpeedKmph)),
                                                wv.getWidth() / 2 - 2 * margin, v.FONT_SMALL);
            int length2 = lines.size();
            if (wv.getDay() == 0 && length + length2 < 5 || wv.getDay() > 0 && length + length2 < 4) {
                for (int i = 0; i < length2; i++) {
                    String line = (String) lines.elementAt(i);
                    g.drawString(line, anchorX, anchorY, Graphics.TOP | Graphics.LEFT);
                    anchorY += fontHeight;
                }
            }
        }
        catch (NumberFormatException nfe) {
            // Well, at least we tried
        }

        // Draw humidity
        String humidity = "Relative Humidity: " + weather.humidity + "%";
        int humidityWidth = g.getFont().stringWidth(humidity);
        anchorX = (width - humidityWidth + r.getHumidity().getWidth()) / 2;
        anchorY = headerHeight;
        if (!weather.humidity.equals("")) {
            anchorY += height / 7 * 4;
            g.drawImage(r.getHumidity(), anchorX - 3, anchorY, Graphics.TOP | Graphics.RIGHT);
            g.drawString(humidity, anchorX, anchorY + r.getHumidity().getHeight() / 2
                    - fontHeight / 2, Graphics.TOP | Graphics.LEFT);
        }
        else {
            anchorY += height / 9 * 6;
        }

        // Draw wind speed
        try {
            double windSpeed = Double.parseDouble(weather.windSpeedKmph);
            String wind = "Wind: " + (int) (UnitUtil.convertVelocity(Settings.KMPH, Settings.windSpeedUnit,
                                                                     windSpeed) + 0.5) + " " + UnitUtil.getWindSpeedUnit(
                    Settings.windSpeedUnit)
                    + ", " + weather.windDirectionPoints;
            Sprite windDirection = wv.getWinddirection();
            g.drawString(wind, anchorX, anchorY - windDirection.getHeight() / 2
                    - fontHeight / 2, Graphics.TOP | Graphics.LEFT);
            windDirection.setRefPixelPosition(anchorX - 3, anchorY);
            windDirection.paint(g);
        }
        catch (NumberFormatException nfe) {
            //No drawing then
        }
    }

    /**
     * Portrait flavor for tiny screens like 128x160
     */
    public static void layoutToTinyPortrait(Weather weather, Graphics g, Visual v, Resources r, WeatherView wv) {
        int width = wv.getWidth();
        int height = wv.getHeight();
        int stretch = height / 6;
        int margin = (int) (0.02 * wv.getWidth());

        // Draw weather icon
        int anchorX = width / 4 * 3;
        int anchorY = height / 7 * 3;
        int anchor = Graphics.VCENTER | Graphics.HCENTER;

        Image weatherIcon = getWeatherIcon(r, wv, weather.iconUrl);
        if (weatherIcon != null) {
            g.drawImage(weatherIcon, anchorX, anchorY, anchor);
        }

        anchorX = width / 6;
        anchorY = height / 2 - 2 * stretch;
        anchor = Graphics.RIGHT | Graphics.TOP;

        g.setColor(v.COLOR_PRIMARY_TEXT);

        if (wv.getDay() > 0) {
            anchorY += 0.3 * stretch;
        }

        // Draw tempereature
        int fontHeight = v.FONT_MEDIUM.getHeight();
        Image termometer = r.getTermometer();
        int iconOffset = (termometer.getHeight() - fontHeight) / 2;
        g.drawImage(r.getTermometer(), anchorX, anchorY - (wv.getDay() == 0 ? iconOffset : 0), anchor);
        g.setFont(v.FONT_MEDIUM);
        fontHeight = g.getFont().getHeight();
        int tempY = anchorY + fontHeight;
        anchorX += margin;
        anchor = Graphics.LEFT | Graphics.TOP;

        if (wv.getDay() == 0) {
            if (Settings.temperatureUnit == Settings.CELSIUS) {
                g.drawString(weather.temperatureC + " °C", anchorX, tempY, Graphics.BOTTOM | Graphics.LEFT);
            }
            else {
                g.drawString(weather.temperatureF + " °F", anchorX, tempY, Graphics.BOTTOM | Graphics.LEFT);
            }
        }
        else {
            String maxTemp = weather.maxTempC + (Settings.temperatureUnit == Settings.CELSIUS ? " °C" : " °F");
            String minTemp = weather.minTempC + (Settings.temperatureUnit == Settings.CELSIUS ? " °C" : " °F");
            int offset = Math.max(g.getFont().stringWidth(maxTemp), g.getFont().stringWidth(minTemp));

            g.drawString(maxTemp, anchorX + offset, tempY, Graphics.BOTTOM | Graphics.RIGHT);
            g.drawString(minTemp, anchorX + offset, tempY + (int) (1.2 * fontHeight), Graphics.BOTTOM | Graphics.RIGHT);

            g.setFont(v.FONT_SMALL);
            g.drawString(" max", anchorX + offset, tempY, Graphics.BOTTOM | Graphics.LEFT);
            g.drawString(" min", anchorX + offset, tempY + (int) (1.2 * fontHeight), Graphics.BOTTOM | Graphics.LEFT);
        }

        anchorX -= margin;
        anchorY += (wv.getDay() == 0) ? stretch : 1.7 * stretch;
        Sprite windDirection = wv.getWinddirection();
        windDirection.setRefPixelPosition(anchorX, anchorY + windDirection.getHeight() - iconOffset);
        windDirection.paint(g);
        g.setFont(v.FONT_MEDIUM);
        anchorX += margin;
        anchor = Graphics.LEFT | Graphics.TOP;
        try {
            double windSpeed = Double.parseDouble(weather.windSpeedKmph);
            String wind = (int) (UnitUtil.convertVelocity(Settings.KMPH, Settings.windSpeedUnit,
                                                          windSpeed) + 0.5) + " " + UnitUtil.getWindSpeedUnit(
                    Settings.windSpeedUnit);
            g.drawString(wind, anchorX, anchorY, Graphics.TOP | Graphics.LEFT);
        }
        catch (NumberFormatException nfe) {
            //No drawing then
        }

        if (wv.getDay() == 0) {
            anchorY += stretch;
            anchorX -= margin;
            anchor = Graphics.RIGHT | Graphics.TOP;
            g.drawImage(r.getHumidity(), anchorX, anchorY - iconOffset, anchor);

            g.setFont(v.FONT_MEDIUM);
            anchorX += margin;
            anchor = Graphics.LEFT | Graphics.TOP;
            if (!weather.humidity.equals("")) {
                g.drawString(weather.humidity + "%", anchorX, anchorY, anchor);
            }
            else {
                g.drawString("-", anchorX, anchorY, anchor);
            }
        }

        // Draw weather description
        anchorX = width / 2;
        anchorY = height / 6 * 4;
        anchor = Graphics.TOP | Graphics.HCENTER;
        g.setFont(v.FONT_SMALL);
        fontHeight = g.getFont().getHeight();

        String description = weather.description;
        try {
            description += ", " + UnitUtil.getBeaufortDesc(Double.parseDouble(weather.windSpeedKmph));
            StringBuffer sb = new StringBuffer(description);
            boolean truncated = false;
            while (v.FONT_SMALL.stringWidth(sb.toString()) > wv.getWidth() - 2 * margin) {
                sb.deleteCharAt(sb.length() - 1);
                truncated = true;
            }
            if (truncated) {
                sb.delete(sb.length() - 3, sb.length() - 1);
                sb.append("...");
                description = sb.toString();
            }
        }
        catch (NumberFormatException nfe) {
            // Well, at least we tried
        }
        g.drawString(description, anchorX, anchorY, anchor);
    }

    /**
     * Landscape flavor
     */
    public static void layoutToLandscape(Weather weather, Graphics g, Visual v, Resources r, WeatherView wv) {
        int width = wv.getWidth();
        int height = wv.getHeight();
        int stretch = height / 6;
        int margin = (int) (0.02 * wv.getWidth());
        int anchorX = width / 4;
        int anchorY = height / 2 - 2 * stretch;
        int anchor = Graphics.RIGHT | Graphics.TOP;

        g.setColor(v.COLOR_PRIMARY_TEXT);

        if (wv.getDay() > 0) {
            anchorY += 0.3 * stretch;
        }
        // Draw tempereature
        g.setFont(v.FONT_SMALL);
        g.drawString("Temp", anchorX, anchorY, anchor);
        g.setFont(v.FONT_MEDIUM);
        int fontHeight = g.getFont().getHeight();
        int tempY = anchorY + fontHeight;
        anchorX += margin;
        anchor = Graphics.LEFT | Graphics.TOP;

        if (wv.getDay() == 0) {
            if (Settings.temperatureUnit == Settings.CELSIUS) {
                g.drawString(weather.temperatureC + " °C", anchorX, tempY, Graphics.BOTTOM | Graphics.LEFT);
            }
            else {
                g.drawString(weather.temperatureF + " °F", anchorX, tempY, Graphics.BOTTOM | Graphics.LEFT);
            }
        }
        else {
            String maxTemp = weather.maxTempC + (Settings.temperatureUnit == Settings.CELSIUS ? " °C" : " °F");
            String minTemp = weather.minTempC + (Settings.temperatureUnit == Settings.CELSIUS ? " °C" : " °F");
            int offset = Math.max(g.getFont().stringWidth(maxTemp), g.getFont().stringWidth(minTemp));

            g.drawString(maxTemp, anchorX + offset, tempY, Graphics.BOTTOM | Graphics.RIGHT);
            g.drawString(minTemp, anchorX + offset, tempY + (int) (1.2 * fontHeight), Graphics.BOTTOM | Graphics.RIGHT);

            g.setFont(v.FONT_SMALL);
            g.drawString(" max", anchorX + offset, tempY, Graphics.BOTTOM | Graphics.LEFT);
            g.drawString(" min", anchorX + offset, tempY + (int) (1.2 * fontHeight), Graphics.BOTTOM | Graphics.LEFT);
        }
        g.setFont(v.FONT_SMALL);
        anchorX -= margin;
        anchorY += (wv.getDay() == 0) ? stretch : 1.7 * stretch;
        anchor = Graphics.RIGHT | Graphics.TOP;
        g.drawString("Wind", anchorX, anchorY, anchor);
        g.setFont(v.FONT_MEDIUM);
        anchorX += margin;
        anchor = Graphics.LEFT | Graphics.TOP;
        try {
            double windSpeed = Double.parseDouble(weather.windSpeedKmph);
            String wind = (int) (UnitUtil.convertVelocity(Settings.KMPH, Settings.windSpeedUnit,
                                                          windSpeed) + 0.5) + " " + UnitUtil.getWindSpeedUnit(
                    Settings.windSpeedUnit);
            g.drawString(wind, anchorX, anchorY, anchor);
            Sprite windDirection = wv.getWinddirection();
            int windWidth = v.FONT_MEDIUM.stringWidth(wind + " ");
            windDirection.setRefPixelPosition(anchorX + windWidth + windDirection.getWidth(),
                                              anchorY + windDirection.getHeight());
            windDirection.paint(g);
        }
        catch (NumberFormatException nfe) {
            //No drawing then
        }

        if (wv.getDay() == 0) {
            g.setFont(v.FONT_SMALL);
            anchorY += stretch;
            anchorX -= margin;
            anchor = Graphics.RIGHT | Graphics.TOP;
            g.drawString("Humidity", anchorX, anchorY, anchor);

            g.setFont(v.FONT_MEDIUM);
            anchorX += margin;
            anchor = Graphics.LEFT | Graphics.TOP;
            if (!weather.humidity.equals("")) {
                g.drawString(weather.humidity + "%", anchorX, anchorY, anchor);
            }
            else {
                g.drawString("-", anchorX, anchorY, anchor);
            }
        }

        // Draw weather icon
        anchorX = width / 4 * 3;
        anchorY = height / 7 * 3;
        anchor = Graphics.VCENTER | Graphics.HCENTER;

        Image weatherIcon = getWeatherIcon(r, wv, weather.iconUrl);
        if (weatherIcon != null) {
            g.drawImage(weatherIcon, anchorX, anchorY - 10, anchor);
        }

        // Draw weather description
        anchorX = width / 2;
        anchorY = height / 6 * 4;
        anchor = Graphics.TOP | Graphics.HCENTER;
        g.setFont(v.FONT_SMALL);
        fontHeight = g.getFont().getHeight();

        String description = weather.description;
        try {
            description += ", " + UnitUtil.getBeaufortDesc(Double.parseDouble(weather.windSpeedKmph));
        }
        catch (NumberFormatException nfe) {
            // Well, at least we tried
        }
        g.drawString(description, anchorX, anchorY, anchor);
    }

    private static Image getWeatherIcon(Resources r, WeatherView wv, String iconUrl) {
        Image weatherIcon = r.getWeatherIcon();
        if (weatherIcon == null) {
            try {
                String url = iconUrl;
                int slashIndex = url.lastIndexOf('/');
                String fileName = url.substring(slashIndex + 1);
                weatherIcon = r.getWeatherIcon(fileName);
                if (wv.getDay() == 0) {
                    wv.updateMode(fileName.indexOf("night") > 0
                            ? Visual.NIGHT_MODE : Visual.DAY_MODE);
                }
            }
            catch (Exception e) {
                System.out.println("Invalid icon url");
            }
        }
        return weatherIcon;
    }
}