/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.ddmuilib;

import com.android.ddmlib.IDevice;
import com.android.ddmlib.Log;
import com.android.ddmlib.RawImage;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

import java.io.IOException;


/**
 * Gather a screen shot from the device and save it to a file.
 */
public class ScreenShotDialog extends Dialog {

    private Label mBusyLabel;
    private Label mImageLabel;
    private Button mSave;
    private IDevice mDevice;


    /**
     * Create with default style.
     */
    public ScreenShotDialog(Shell parent) {
        this(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
    }

    /**
     * Create with app-defined style.
     */
    public ScreenShotDialog(Shell parent, int style) {
        super(parent, style);
    }

    /**
     * Prepare and display the dialog.
     * @param device The {@link IDevice} from which to get the screenshot.
     */
    public void open(IDevice device) {
        mDevice = device;

        Shell parent = getParent();
        Shell shell = new Shell(parent, getStyle());
        shell.setText("Device Screen Capture");

        createContents(shell);
        shell.pack();
        shell.open();

        updateDeviceImage(shell);

        Display display = parent.getDisplay();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }

    }

    /*
     * Create the screen capture dialog contents.
     */
    private void createContents(final Shell shell) {
        GridData data;

        shell.setLayout(new GridLayout(3, true));

        // title/"capturing" label
        mBusyLabel = new Label(shell, SWT.NONE);
        mBusyLabel.setText("Preparing...");
        data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
        data.horizontalSpan = 3;
        mBusyLabel.setLayoutData(data);

        // space for the image
        mImageLabel = new Label(shell, SWT.BORDER);
        data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
        data.horizontalSpan = 3;
        mImageLabel.setLayoutData(data);
        Display display = shell.getDisplay();
        mImageLabel.setImage(ImageHelper.createPlaceHolderArt(display, 50, 50, display.getSystemColor(SWT.COLOR_BLUE)));

        // "refresh" button
        Button refresh = new Button(shell, SWT.PUSH);
        refresh.setText("Refresh");
        data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
        data.widthHint = 80;
        refresh.setLayoutData(data);
        refresh.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                updateDeviceImage(shell);
            }
        });

        // "save" button
        mSave = new Button(shell, SWT.PUSH);
        mSave.setText("Save");
        data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
        data.widthHint = 80;
        mSave.setLayoutData(data);
        mSave.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                saveImage(shell);
            }
        });

        // "done" button
        Button done = new Button(shell, SWT.PUSH);
        done.setText("Done");
        data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
        data.widthHint = 80;
        done.setLayoutData(data);
        done.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                shell.close();
            }
        });

        shell.setDefaultButton(done);
    }

    /*
     * Capture a new image from the device.
     */
    private void updateDeviceImage(Shell shell) {
        mBusyLabel.setText("Capturing...");     // no effect

        shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT));

        Image image = getDeviceImage();
        if (image == null) {
            Display display = shell.getDisplay();
            image = ImageHelper.createPlaceHolderArt(display, 320, 240, display.getSystemColor(SWT.COLOR_BLUE));
            mSave.setEnabled(false);
            mBusyLabel.setText("Screen not available");
        } else {
            mSave.setEnabled(true);
            mBusyLabel.setText("Captured image:");
        }

        mImageLabel.setImage(image);
        mImageLabel.pack();
        shell.pack();

        // there's no way to restore old cursor; assume it's ARROW
        shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_ARROW));
    }

    /*
     * Grab an image from an ADB-connected device.
     */
    private Image getDeviceImage() {
        RawImage rawImage;

        try {
            rawImage = mDevice.getScreenshot();
        }
        catch (IOException ioe) {
            Log.w("ddms", "Unable to get frame buffer: " + ioe.getMessage());
            return null;
        }

        // device/adb not available?
        if (rawImage == null)
            return null;

        // convert raw data to an Image
        assert rawImage.bpp == 16;
        PaletteData palette = new PaletteData(0xf800, 0x07e0, 0x001f);
        ImageData imageData = new ImageData(rawImage.width, rawImage.height,
            rawImage.bpp, palette, 1, rawImage.data);

        return new Image(getParent().getDisplay(), imageData);
    }

    /*
     * Prompt the user to save the image to disk.
     */
    private void saveImage(Shell shell) {
        FileDialog dlg = new FileDialog(shell, SWT.SAVE);
        String fileName;

        dlg.setText("Save image...");
        dlg.setFileName("device.png");
        dlg.setFilterPath(DdmUiPreferences.getStore().getString("lastImageSaveDir"));
        dlg.setFilterNames(new String[] {
            "PNG Files (*.png)"
        });
        dlg.setFilterExtensions(new String[] {
            "*.png" //$NON-NLS-1$
        });

        fileName = dlg.open();
        if (fileName != null) {
            DdmUiPreferences.getStore().setValue("lastImageSaveDir", dlg.getFilterPath());

            Log.i("ddms", "Saving image to " + fileName);
            ImageData imageData = mImageLabel.getImage().getImageData();

            try {
                WritePng.savePng(fileName, imageData);
            }
            catch (IOException ioe) {
                Log.w("ddms", "Unable to save " + fileName + ": " + ioe);
            }

            if (false) {
                ImageLoader loader = new ImageLoader();
                loader.data = new ImageData[] { imageData };
                // PNG writing not available until 3.3?  See bug at:
                //  https://bugs.eclipse.org/bugs/show_bug.cgi?id=24697
                // GIF writing only works for 8 bits
                // JPEG uses lossy compression
                // BMP has screwed-up colors
                loader.save(fileName, SWT.IMAGE_JPEG);
            }
        }
    }

}

