/*
 * Copyright 2015 Gerhard Klostermeier
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


package de.syss.NfcTool.Activities;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.NfcA;
import android.os.Bundle;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import de.syss.NfcTool.Common;
import de.syss.NfcTool.DitheringUtils;
import de.syss.NfcTool.ImageSaver;
import de.syss.NfcTool.R;


@SuppressWarnings("deprecation")
/**
 * Calculate the BCC value of a given UID.
 * @author Gerhard Klostermeier
 */
public class NfcEpdTool extends BasicActivity {

    private static final String LOG_TAG = "NfcEpd";
    private EditText mUid;
    private ProgressBar mProgressBar;

    private ImageView mImageSource;
    private ImageView mImagePreview;
    private TextView mLog;

    private TextView mTextViewAckCnt;
    private TextView mTextViewNackCnt;
    private TextView mTextViewCurrentStatus;

    int nfcAckCnt;
    int nfcNackCnt;

    void UpdateStat(int progress, String msg)
    {

        NfcEpdTool v = this;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mProgressBar.setProgress(progress);
                mTextViewAckCnt.setText(Integer.toString(nfcAckCnt));
                mTextViewNackCnt.setText(Integer.toString(nfcNackCnt));
                mTextViewCurrentStatus.setText(msg);
            }
        });
    }

    static NfcAdapter mNfcAdapter;
    /**
     * Initialize the some member variables.
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_epd_tool);

        mUid = findViewById(R.id.editTextBccToolUid);
        mProgressBar = findViewById(R.id.progressBar);
        mImageSource = findViewById(R.id.imageView);
        mImagePreview = findViewById(R.id.imageView2);
        mLog = findViewById(R.id.logText);

        mTextViewAckCnt = findViewById(R.id.textViewAckCnt);
        mTextViewNackCnt = findViewById(R.id.textViewNackCnt);
        mTextViewCurrentStatus = findViewById(R.id.textViewCurrentStatus);



        byte crc = Crc8(new byte[]{1,2,3,4,5,6,7,8,9}, 9);
        mTextViewCurrentStatus.setText(String.format("%02X", crc));
    }

    public static void enableNfcForegroundDispatch(Activity targetActivity) {
        if (mNfcAdapter != null && mNfcAdapter.isEnabled()) {
            Intent intent = new Intent(targetActivity,
                targetActivity.getClass()).addFlags(
                Intent.FLAG_ACTIVITY_SINGLE_TOP);
            PendingIntent pendingIntent = PendingIntent.getActivity(
                targetActivity, 0, intent, PendingIntent.FLAG_MUTABLE);

            IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
            try {
                ndef.addDataType("*/*");
            } catch (IntentFilter.MalformedMimeTypeException e) {
                throw new RuntimeException();
            }
            try {
                mNfcAdapter.enableForegroundDispatch(
                    targetActivity, pendingIntent, new IntentFilter[] { ndef, }, new String[][]{
                        new String[]{NfcA.class.getName()}});
            } catch (IllegalStateException ex) {
                Log.d(LOG_TAG, "Error: Could not enable the NFC foreground" +
                    "dispatch system. The activity was not in foreground.");
            }
        }
    }
    /**
     * Enable NFC foreground dispatch system.
     * @see Common#disableNfcForegroundDispatch(Activity)
     */
    @Override
    public void onResume() {
        super.onResume();
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        enableNfcForegroundDispatch(this);
    }

    /**
     * Disable NFC foreground dispatch system.
     * @see Common#disableNfcForegroundDispatch(Activity)
     */
    @Override
    public void onPause() {
        super.onPause();
        Common.disableNfcForegroundDispatch(this);

    }
    /**
     * Handle new Intent as a new tag Intent and if the tag/device does not
     * support MIFARE Classic, then run {@link TagInfoTool}.
     * @see Common#treatAsNewTag(Intent, android.content.Context)
     * @see TagInfoTool
     */
    @Override
    public void onNewIntent(Intent intent) {
        int typeCheck = Common.treatAsNewTag(intent, this);
        if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
            Tag rawTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            NfcA ntag = NfcA.get(rawTag);

            SetCurrentTag(rawTag);
            new Thread() {
                @Override
                public void run() {
                    String blkRead = "";


                    try {
                        nfcAckCnt = 0;
                        nfcNackCnt = 0;
                        ntag.connect();
                        for (byte i = 0; i < 0x3A; i += 4) {
                            byte[] readBack = ntag.transceive(new byte[]{0x3A, i, (byte) (i + 0x04)});
                            String readData = Common.bytes2Hex(readBack);
                            blkRead += readData + "\n";
                            // Thread.sleep(0);
                        }
                        SetLog(blkRead);
                        UpdateStat(100, "等待握手");

                        blkRead += "等待握手\n";
                        SetLog(blkRead);
                        UpdateStat(0, "等待握手");
                        WaitRfDataReady(ntag);
                        ReadSram(ntag);
                        blkRead += "等待写入握手响应\n";
                        SetLog(blkRead);
                        UpdateStat(0, "等待写入握手响应");
                        WaitRfWrite(ntag);
                        blkRead += "写入握手响应\n";
                        SetLog(blkRead);
                        UpdateStat(0, "写入握手响应");
                        WriteSram(ntag, new byte[64]);
                        blkRead += "完成握手\n";
                        SetLog(blkRead);
                        UpdateStat(0, "完成握手");
                        long startTime = SystemClock.uptimeMillis();
                        int pi = -1;
                        byte[] buf = new byte[64];
                        while (true) {
                            WaitRfDataReady(ntag);
                            byte[] ack = ReadAck(ntag);
                            byte ackVal = ack[12];
                            if (ackVal == 'A') {
                                nfcAckCnt++;
                                pi++;
                                if (pi >= 500) {
                                    break;
                                }
                                for (int j = 0; j < 60; ++j) {
                                    buf[j] = picBuf[pi][j];
                                }
                                byte crc = Crc8(buf, 63);
                                buf[63] = crc;
                            } else {
                                nfcNackCnt++;
                            }
                            WaitRfWrite(ntag);
                            WriteSram(ntag, buf);
                            UpdateStat(pi * 100 / 500, String.format("传输中%d/500 ACK:%02X CRC:%02X \n" + Common.bytes2Hex(ack), pi, ackVal, buf[63]));
                            // blkRead += String.format("R%02X\n| %03d A%02X T%02X ", rdbkcrc, pi, ack[12], buf[62]);
                        }
                        long endTime = SystemClock.uptimeMillis();
                        blkRead += "传输完成";
                        SetLog(blkRead);
                        UpdateStat(100,  String.format("传输完成 用时%.3fs", (endTime - startTime)/1000.0));

                    } catch (IOException e) {
                        blkRead += "IO失败";
                        SetLog(blkRead);
                        UpdateStat(100, "IO失败");
                        MakeToast("IO失败");
                    } catch (InterruptedException e) {
                        blkRead += "失败";
                        SetLog(blkRead);
                        UpdateStat(100, "传输中断");
                        MakeToast("传输中断");
                    } finally {
                        try {
                            ntag.close();
                        } catch (IOException e) {

                        }
                    }
                }
            }.start();
        } else if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
            // NfcAdapter.EXTRA_NDEF_MESSAGES
        }
    }


    boolean WaitRfDataReady(NfcA tag) throws InterruptedException {
        int retry = 10;
        while (retry-- >= 0){
            try {
                byte[] rd = tag.transceive(new byte[]{0x30, (byte) 0xEC});
                byte nc_reg = rd[0];
                byte ns_reg = rd[6];
                if (0 != (ns_reg & (0b1000))) {
                    return true;
                }
            } catch (IOException e) {
                MakeToast("WaitRfDataReady fail" + Integer.toString(retry));
                Log.e(LOG_TAG, "WaitRfDataReady fail" + Integer.toString(retry));
                Thread.sleep(100);
            }
        }
        throw new InterruptedException();
    }

    boolean WaitRfWrite(NfcA tag) throws InterruptedException {
        int retry = 10;
        while (retry-- >= 0){
            try {
                byte[] rd = tag.transceive(new byte[]{0x30, (byte) 0xEC});
                byte nc_reg = rd[0];
                byte ns_reg = rd[6];
                boolean pthruOn = (0 != (nc_reg & (1 << 6)));
                boolean transferDirNfc2Iic = (0 != (nc_reg & (1 << 0)));
                if (pthruOn && transferDirNfc2Iic) {
                    return true;
                }
            } catch (IOException e) {
                MakeToast("WaitRfWrite fail" + Integer.toString(retry));
                Log.e(LOG_TAG, "WaitRfWrite fail" + Integer.toString(retry));
                Thread.sleep(100);
            }
        }
        throw new InterruptedException();
    }
    byte[] ReadAck(NfcA tag) throws InterruptedException {
        int retry = 10;
        while (retry-- >= 0){
            try {
                // byte[] rd = tag.transceive(new byte[]{0x3A, (byte) 0xF0, (byte) 0xFF});
                byte[] rd = tag.transceive(new byte[]{0x30, (byte) 0xFC});
                return rd;
            } catch (IOException e) {
                MakeToast("ReadAck fail" + Integer.toString(retry));
                Log.e(LOG_TAG, "ReadAck fail" + Integer.toString(retry));
                Thread.sleep(100);
            }
        }
        throw new InterruptedException();
    }

    boolean WriteSram(NfcA tag, byte[] data) throws InterruptedException {
        byte[] txBuf = new byte[3+data.length];
        txBuf[0] = (byte) 0xA6;
        txBuf[1] = (byte) 0xF0;
        txBuf[2] = (byte) 0xFF;
        for (int i = 0; i < data.length; ++i) {
            txBuf[3+i] = data[i];
        }
        int retry = 10;
        while (retry-- >= 0){
            try {
                tag.setTimeout(300);
                byte[] rd = tag.transceive(txBuf);
                return rd.equals(new byte[] {0x0A});
            } catch (IOException e) {
                MakeToast("WriteSram fail" + Integer.toString(retry));
                Log.e(LOG_TAG, "WriteSram fail" + Integer.toString(retry));
                Thread.sleep(100);
            }
        }
        throw new InterruptedException();
    }
    byte[] ReadSram(NfcA tag) throws InterruptedException {
        int retry = 10;
        while (retry-- >= 0){
            try {
                byte[] rd = tag.transceive(new byte[]{0x3A, (byte) 0xF0, (byte) 0xFF});
                Log.d(LOG_TAG, "Read:" + Common.bytes2Hex(rd));
                return rd;
            } catch (IOException e) {
                MakeToast("ReadSram fail" + Integer.toString(retry));
                Log.e(LOG_TAG, "ReadSram fail" + Integer.toString(retry));
                Thread.sleep(100);
            }
        }
        throw new InterruptedException();
    }


    void SetLog(String log)
    {
        NfcEpdTool v = this;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mLog.setText(log);
            }
        });
    }
    void SetCurrentTag(Tag tag)
    {
        NfcEpdTool v = this;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mUid.setText(Common.bytes2Hex(tag.getId()));
            }
        });
    }
    void MakeToast(String s)
    {
        NfcEpdTool v = this;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(v, s, Toast.LENGTH_SHORT).show();
            }
        });
    }

    byte Crc8(byte[] buf, int len)
    {
        final byte[] crc_table = new byte[]
        {
            (byte)0x00,(byte)0x31,(byte)0x62,(byte)0x53,(byte)0xc4,(byte)0xf5,(byte)0xa6,(byte)0x97,(byte)0xb9,(byte)0x88,(byte)0xdb,(byte)0xea,(byte)0x7d,(byte)0x4c,(byte)0x1f,(byte)0x2e,
            (byte)0x43,(byte)0x72,(byte)0x21,(byte)0x10,(byte)0x87,(byte)0xb6,(byte)0xe5,(byte)0xd4,(byte)0xfa,(byte)0xcb,(byte)0x98,(byte)0xa9,(byte)0x3e,(byte)0x0f,(byte)0x5c,(byte)0x6d,
            (byte)0x86,(byte)0xb7,(byte)0xe4,(byte)0xd5,(byte)0x42,(byte)0x73,(byte)0x20,(byte)0x11,(byte)0x3f,(byte)0x0e,(byte)0x5d,(byte)0x6c,(byte)0xfb,(byte)0xca,(byte)0x99,(byte)0xa8,
            (byte)0xc5,(byte)0xf4,(byte)0xa7,(byte)0x96,(byte)0x01,(byte)0x30,(byte)0x63,(byte)0x52,(byte)0x7c,(byte)0x4d,(byte)0x1e,(byte)0x2f,(byte)0xb8,(byte)0x89,(byte)0xda,(byte)0xeb,
            (byte)0x3d,(byte)0x0c,(byte)0x5f,(byte)0x6e,(byte)0xf9,(byte)0xc8,(byte)0x9b,(byte)0xaa,(byte)0x84,(byte)0xb5,(byte)0xe6,(byte)0xd7,(byte)0x40,(byte)0x71,(byte)0x22,(byte)0x13,
            (byte)0x7e,(byte)0x4f,(byte)0x1c,(byte)0x2d,(byte)0xba,(byte)0x8b,(byte)0xd8,(byte)0xe9,(byte)0xc7,(byte)0xf6,(byte)0xa5,(byte)0x94,(byte)0x03,(byte)0x32,(byte)0x61,(byte)0x50,
            (byte)0xbb,(byte)0x8a,(byte)0xd9,(byte)0xe8,(byte)0x7f,(byte)0x4e,(byte)0x1d,(byte)0x2c,(byte)0x02,(byte)0x33,(byte)0x60,(byte)0x51,(byte)0xc6,(byte)0xf7,(byte)0xa4,(byte)0x95,
            (byte)0xf8,(byte)0xc9,(byte)0x9a,(byte)0xab,(byte)0x3c,(byte)0x0d,(byte)0x5e,(byte)0x6f,(byte)0x41,(byte)0x70,(byte)0x23,(byte)0x12,(byte)0x85,(byte)0xb4,(byte)0xe7,(byte)0xd6,
            (byte)0x7a,(byte)0x4b,(byte)0x18,(byte)0x29,(byte)0xbe,(byte)0x8f,(byte)0xdc,(byte)0xed,(byte)0xc3,(byte)0xf2,(byte)0xa1,(byte)0x90,(byte)0x07,(byte)0x36,(byte)0x65,(byte)0x54,
            (byte)0x39,(byte)0x08,(byte)0x5b,(byte)0x6a,(byte)0xfd,(byte)0xcc,(byte)0x9f,(byte)0xae,(byte)0x80,(byte)0xb1,(byte)0xe2,(byte)0xd3,(byte)0x44,(byte)0x75,(byte)0x26,(byte)0x17,
            (byte)0xfc,(byte)0xcd,(byte)0x9e,(byte)0xaf,(byte)0x38,(byte)0x09,(byte)0x5a,(byte)0x6b,(byte)0x45,(byte)0x74,(byte)0x27,(byte)0x16,(byte)0x81,(byte)0xb0,(byte)0xe3,(byte)0xd2,
            (byte)0xbf,(byte)0x8e,(byte)0xdd,(byte)0xec,(byte)0x7b,(byte)0x4a,(byte)0x19,(byte)0x28,(byte)0x06,(byte)0x37,(byte)0x64,(byte)0x55,(byte)0xc2,(byte)0xf3,(byte)0xa0,(byte)0x91,
            (byte)0x47,(byte)0x76,(byte)0x25,(byte)0x14,(byte)0x83,(byte)0xb2,(byte)0xe1,(byte)0xd0,(byte)0xfe,(byte)0xcf,(byte)0x9c,(byte)0xad,(byte)0x3a,(byte)0x0b,(byte)0x58,(byte)0x69,
            (byte)0x04,(byte)0x35,(byte)0x66,(byte)0x57,(byte)0xc0,(byte)0xf1,(byte)0xa2,(byte)0x93,(byte)0xbd,(byte)0x8c,(byte)0xdf,(byte)0xee,(byte)0x79,(byte)0x48,(byte)0x1b,(byte)0x2a,
            (byte)0xc1,(byte)0xf0,(byte)0xa3,(byte)0x92,(byte)0x05,(byte)0x34,(byte)0x67,(byte)0x56,(byte)0x78,(byte)0x49,(byte)0x1a,(byte)0x2b,(byte)0xbc,(byte)0x8d,(byte)0xde,(byte)0xef,
            (byte)0x82,(byte)0xb3,(byte)0xe0,(byte)0xd1,(byte)0x46,(byte)0x77,(byte)0x24,(byte)0x15,(byte)0x3b,(byte)0x0a,(byte)0x59,(byte)0x68,(byte)0xff,(byte)0xce,(byte)0x9d,(byte)0xac
        };
        byte crc = 0;
        for (int i = 0; i < len; ++i) {
            crc = crc_table[(crc ^ buf[i]) & 0xFF];
        }
        return crc;
    }

    public static final int PICK_IMAGE = 1;

    public void pickImage() {
        // 只激活系统的图片选择器
        Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
        intent.setType("image/*");
        startActivityForResult(intent, PICK_IMAGE);
    }

    public static final int CROP_IMAGE = 2; // 新增一个 Activity 回调状态码
    private Uri mCropOutputUri;

    private Bitmap resizeAndCenterCrop(Bitmap source, int newWidth, int newHeight) {
        int sourceWidth = source.getWidth();
        int sourceHeight = source.getHeight();

        // 计算缩放比例
        float xScale = (float) newWidth / sourceWidth;
        float yScale = (float) newHeight / sourceHeight;
        float scale = Math.max(xScale, yScale); // 保持等比例缩放，不拉伸

        // 缩放后的临时尺寸
        float scaledWidth = scale * sourceWidth;
        float scaledHeight = scale * sourceHeight;

        // 计算居中裁剪的起始坐标
        float left = (newWidth - scaledWidth) / 2;
        float top = (newHeight - scaledHeight) / 2;

        // 创建目标 400x300 的画布
        Bitmap targetBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
        android.graphics.Canvas canvas = new android.graphics.Canvas(targetBitmap);

        android.graphics.Matrix matrix = new android.graphics.Matrix();
        matrix.postScale(scale, scale);
        matrix.postTranslate(left, top);

        android.graphics.Paint paint = new android.graphics.Paint();
        paint.setFilterBitmap(true);

        canvas.drawBitmap(source, matrix, paint);
        return targetBitmap;
    }

    Bitmap currentSource = null;
    byte[][] picBuf = null;
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode != RESULT_OK) {
            return;
        }

        if (requestCode == PICK_IMAGE) {
            if (data != null && data.getData() != null) {
                Uri selectedImageUri = data.getData();
                try {
                    // 1. 从图库的 Uri 拉取原始大图
                    Bitmap originalBitmap = BitmapFactory.decodeStream(
                        getContentResolver().openInputStream(selectedImageUri)
                    );

                    if (originalBitmap == null) {
                        MakeToast("加载原始图片失败");
                        return;
                    }

                    // 2. 内存自动等比例居中裁剪为 400x300
                    currentSource = resizeAndCenterCrop(originalBitmap, 400, 300);

                    // 释放原始大图内存
                    if (originalBitmap != currentSource) {
                        originalBitmap.recycle();
                    }

                    mImageSource.setImageBitmap(currentSource);

                    // 3. 调用兼容低版本的抖动算法
                    Bitmap dithered = DitheringUtils.dithering(currentSource);
                    mImagePreview.setImageBitmap(dithered);
                    mImagePreview.setScaleType(ImageView.ScaleType.FIT_CENTER);

                    picBuf = new byte[500][60];

                    byte v = 0;
                    byte bitCnt = 0;
                    int pidx = 0;
                    int bidx = 0;

                    int width = dithered.getWidth();
                    int height = dithered.getHeight();

                    // 【核心修改】：将像素点阵一次性读入内存数组，避免高频调用 getPixel 且完全丢弃 Color.valueOf
                    int[] pixels = new int[width * height];
                    dithered.getPixels(pixels, 0, width, 0, 0, width, height);

                    // 第一阶段循环：提取第一层像素颜色数据
                    for (int i = 0; i < pixels.length; i++) {
                        int color = pixels[i];
                        // 提取 R, G, B 分量 (值在 0~255 之间)
                        int r = (color >> 16) & 0xFF;
                        int b = color & 0xFF;

                        // 对应原代码的 (c.red() > 0.1) && (c.blue() > 0.1)
                        // 0.1 换算到 0~255 的区间大约是 25.5，这里取 25 即可
                        if ((r > 25) && (b > 25)) {
                            v |= 1 << (7 - bitCnt);
                        }
                        bitCnt++;
                        if (bitCnt >= 8) {
                            bitCnt = 0;
                            picBuf[pidx][bidx++] = v;
                            v = 0;
                            if (bidx >= 60) {
                                bidx = 0;
                                pidx++;
                            }
                        }
                    }

                    // 重置计数器，进行第二阶段循环
                    v = 0;
                    bitCnt = 0;

                    // 第二阶段循环：提取第二层像素颜色数据
                    for (int i = 0; i < pixels.length; i++) {
                        int color = pixels[i];
                        int r = (color >> 16) & 0xFF;
                        int b = color & 0xFF;

                        // 对应原代码的 (c.red() < 0.1) || (c.blue() > 0.1)
                        if ((r < 25) || (b > 25)) {
                            v |= 1 << (7 - bitCnt);
                        }
                        bitCnt++;
                        if (bitCnt >= 8) {
                            bitCnt = 0;
                            picBuf[pidx][bidx++] = v;
                            v = 0;
                            if (bidx >= 60) {
                                bidx = 0;
                                pidx++;
                            }
                        }
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                    MakeToast("图片点阵化解析异常");
                }
            } else {
                MakeToast("选择图片失败");
            }
        }
    }

    private String SaveToInternalStorage(Bitmap bitmapImage){
        ContextWrapper cw = new ContextWrapper(getApplicationContext());
        // path to /data/data/yourapp/app_data/imageDir
        File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
        // Create imageDir
        File mypath=new File(directory,"profile.jpg");

        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(mypath);
            // Use the compress method on the BitMap object to write image to the OutputStream
            bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return directory.getAbsolutePath();
    }
    public void onSavePictureClicked(View view)
    {
        if (currentSource != null) {
            if (new ImageSaver(this).
                setFileName("myImage.png").
                setDirectoryName("images").
                save(currentSource)) {
                MakeToast("Saved");
            }
        }
    }

    public void onSelectPictureClicked(View view)
    {
        pickImage();
    }
}
