public static final String FileNamePartSimpleDateFormat = "yyyy-MM-dd'T'HH-mm-ss-"; public static final String PLUGIN_COMMAND_ID_CLIP_FILE_TO_EVERNOTE = "org.lttpp.eemory.commands.ClipFileToEvernote"; public static final String PLUGIN_COMMAND_ID_CLIP_SCREENSHOT_TO_EVERNOTE = "org.lttpp.eemory.commands.ClipScreenshotToEvernote"; public static final String PLUGIN_COMMAND_ID_CLIP_SELECTION_TO_EVERNOTE = "org.lttpp.eemory.commands.ClipSelectionToEvernote"; public static final String PLUGIN_COMMAND_ID_CLIP_TO_EVERNOTE = "org.lttpp.eemory.commands.ClipToEvernote"; public static final String PLUGIN_COMMAND_ID_CONFIGURATIONS = "org.lttpp.eemory.commands.Configurations"; public static final String PLUGIN_COMMAND_PARAM_ID = "org.lttpp.eemory.command.parameter"; public static final String PLUGIN_SETTINGS_KEY_GUID = "guid"; public static final String PLUGIN_SETTINGS_KEY_NAME = "name"; public static final String PLUGIN_SETTINGS_KEY_OBJECT = "object"; public static final String PLUGIN_SETTINGS_KEY_TOKEN = "token"; public static final String PLUGIN_SETTINGS_KEY_TYPE = "type"; public static final String PLUGIN_SETTINGS_SECTION_COMMENTS = "comments"; public static final String PLUGIN_SETTINGS_SECTION_NOTE = "note"; public static final String PLUGIN_SETTINGS_SECTION_NOTEBOOK = "notebook"; public static final String PLUGIN_SETTINGS_SECTION_TAGS = "tags"; public static final int TAB_WIDTH = 4; public static final String TAGS_SEPARATOR = ConstantsUtil.COMMA; public class Messages extends NLS {

    private static final String BUNDLE_NAME = "messages"; //$NON-NLS-1$

    public static String Plugin_Configs_Shell_Title;
    public static String Plugin_Configs_QuickOrgnize_Shell_Title;
    public static String Plugin_Configs_Title;
    public static String Plugin_Configs_Message;
    public static String Plugin_Configs_Organize;
    public static String Plugin_Configs_Notebook;
    public static String Plugin_Configs_Note;
    public static String Plugin_Configs_Tags;
    public static String Plugin_Configs_Notebook_Hint;
    public static String Plugin_Configs_Note_Hint;
    public static String Plugin_Configs_Tags_Hint;
    public static String Plugin_Configs_Comments;
    public static String Plugin_Configs_Refresh;
    public static String Plugin_Configs_Authenticating;
    public static String Plugin_Configs_FetchingNotebooks;
    public static String Plugin_Configs_FetchingNotes;
    public static String Plugin_Configs_FetchingTags;
    public static String Plugin_Runtime_ClipFileToEvernote;
    public static String Plugin_Runtime_ClipSelectionToEvernote;
    public static String Plugin_Runtime_ClipScreenshotToEvernote_Hint;
    public static String Plugin_Runtime_CreateNewNote;
    public static String Plugin_Runtime_CreateNewNoteInNotebook;
    public static String Plugin_Runtime_ClipToDefault;
    public static String Plugin_Runtime_CreateNewNoteWithGivenName;
    public static String Plugin_Runtime_CreateNewNoteWithGivenNameInNotebook;
    public static String Plugin_Runtime_ClipToNotebook_Default;
    public static String Plugin_OutOfDate;
    public static String Plugin_Error_Occurred;
    public static String Plugin_Error_OutOfDate;
    public static String Plugin_Error_NoFile;
    public static String Plugin_Error_NoText;
    public static String Plugin_OAuth_Cancel;
    public static String Plugin_OAuth_Copy;

    public static String Plugin_OAuth_TokenNotConfigured;
    public static String Plugin_OAuth_Title;
    public static String Plugin_OAuth_Configure;
    public static String Plugin_OAuth_NotNow;
    public static String Plugin_OAuth_Waiting;
    public static String Plugin_OAuth_Confirm;
    public static String Plugin_OAuth_AuthExpired_Message;
    public static String Plugin_OAuth_AuthExpired_Title;
    public static String Plugin_OAuth_AuthExpired_ReAuth;
    public static String Plugin_OAuth_DoItManually;
    public static String Plugin_OAuth_SWITCH_YXBJ;
    public static String Plugin_OAuth_SWITCH_INTL;

    public static String DOM_Error0;
    public static String DOM_Error1;
    public static String DOM_Error2;
    public static String DOM_Error3;
    public static String DOM_Error4;
    public static String DOM_Error5;
    public static String DOM_Error6;
    public static String DOM_Error7;
    public static String DOM_Error8;
    public static String DOM_Error9;
    public static String Throwable_IllegalArgumentException_Message;
    public static String Throwable_NotSerializable_Message;

    // For Debug
    public static String Plugin_Debug_Default_Font_Style;
    public static String Plugin_Debug_StyleRange_Font_Style;
    public static String Plugin_Debug_FinalConcluded_Font_Style;
    public static String Plugin_Debug_NewClipper;
    public static String Plugin_Debug_IsFullScreenSupported;
    public static String Plugin_Debug_CapturedScreenshot;
    public static String Plugin_Debug_NoScreenCaptureProcessor;

    static {
        // initialize resource bundle
        NLS.initializeMessages(BUNDLE_NAME, Messages.class);
    }

    private Messages() {
    }

} public abstract class EeClipper {

    private boolean valid = true;

    public abstract void clipFile(ENNote args) throws Exception;

    public abstract void clipSelection(ENNote args) throws Exception;

    public abstract Map<String, ENObject> listNotebooks() throws Exception;

    public abstract Map<String, ENNote> listNotesWithinNotebook(ENNote args) throws Exception;

    public abstract List<String> listTags() throws Exception;

    public boolean isValid() {
        return valid;
    };

    public void setInvalid() {
        valid = false;
    };

} public class ENNoteImpl extends ENObjectImpl implements ENNote {

    private ENObject notebook;
    private List<List<StyleText>> content;
    private List<File> attachments;
    private List<String> tags;
    private String comments;
    private int tabWidth;

    public ENNoteImpl() {
        content = ListUtil.list();
        attachments = ListUtil.list();
        tags = ListUtil.list();
    }

    public ENNoteImpl(final String guid) {
        super(guid);
        content = ListUtil.list();
        attachments = ListUtil.list();
        tags = ListUtil.list();
    }

    public ENNoteImpl(final String name, final String guid) {
        super(name, guid);
        content = ListUtil.list();
        attachments = ListUtil.list();
        tags = ListUtil.list();
    }

    @Override
    public ENObject getNotebook() {
        if (notebook == null) {
            notebook = new ENObjectImpl();
        }
        return notebook;
    }

    @Override
    public void setNotebook(final ENObject notebook) {
        this.notebook = notebook;
    }

    @Override
    public List<List<StyleText>> getContent() {
        return content;
    }

    @Override
    public void setContent(final List<List<StyleText>> content) {
        this.content = content;
    }

    @Override
    public List<File> getAttachments() {
        return attachments;
    }

    @Override
    public void setAttachments(final List<File> attachments) {
        this.attachments = attachments;
    }

    @Override
    public List<String> getTags() {
        return tags;
    }

    @Override
    public void setTags(final List<String> tags) {
        this.tags = tags;
    }

    @Override
    public String getComments() {
        return comments;
    }

    @Override
    public void setComments(final String comments) {
        this.comments = comments;
    }

    @Override
    public int getTabWidth() {
        return tabWidth;
    }

    @Override
    public void setTabWidth(final int tabWidth) {
        this.tabWidth = tabWidth;
    }

    /**
     * Adopt if not null/empty/blank
     */
    @Override
    public void adopt(final ENObject obj) {

        super.adopt(obj);

        if (!(obj instanceof ENNote)) {
            return;
        }
        ENNote note = (ENNote) obj;

        if (note.getNotebook() != null) {
            getNotebook().adopt(note.getNotebook());
        }

        if (!ListUtil.isNullOrEmptyList(note.getContent())) {
            setContent(note.getContent());
        }

        if (!ListUtil.isNullOrEmptyList(note.getAttachments())) {
            setAttachments(note.getAttachments());
        }

        if (!ListUtil.isNullOrEmptyList(note.getTags())) {
            setTags(note.getTags());
        }

        if (StringUtils.isNotBlank(note.getComments())) {
            setComments(note.getComments());
        }
    }

    public static ENNote forGuid(final String guid) {
        return new ENNoteImpl(guid);
    }

    public static ENNote forNameAndGuid(final String name, final String guid) {
        return new ENNoteImpl(name, guid);
    }

    public static ENNote forNotebook(final ENObject notebook) {
        ENNote n = new ENNoteImpl();
        if (notebook != null) {
            n.getNotebook().setName(notebook.getName()); // maybe no use but just in case
            n.getNotebook().setGuid(notebook.getGuid());
            n.getNotebook().setType(notebook.getType());
            n.getNotebook().setLinkedObject(notebook.getLinkedObject());
        }
        return n;
    }

} public enum ENObjectType {

    NORMAL {
        @Override
        public String toString() {
            return Constants.ENOBJECT_TYPE_NORMAL;
        }
    },
    LINKED {
        @Override
        public String toString() {
            return Constants.ENOBJECT_TYPE_LINKED;
        }
    },
    BUSINESS {
        @Override
        public String toString() {
            return Constants.ENOBJECT_TYPE_BUSINESS;
        }
    };

    public static ENObjectType forName(final String name) throws IllegalArgumentException {
        ENObjectType[] values = ENObjectType.values();
        for (ENObjectType value : values) {
            if (value.toString().equalsIgnoreCase(name)) {
                return value;
            }
        }
        LogUtil.debug(Messages.bind(Messages.Throwable_IllegalArgumentException_Message, name));
        throw new IllegalArgumentException(Messages.bind(Messages.Throwable_IllegalArgumentException_Message, name));
    }

} public interface ENNote extends ENObject {

    public ENObject getNotebook();

    public void setNotebook(ENObject notebook);

    public List<List<StyleText>> getContent();

    public void setContent(List<List<StyleText>> content);

    public List<File> getAttachments();

    public void setAttachments(List<File> files);

    public List<String> getTags();

    public abstract void setTags(List<String> tags);

    public abstract String getComments();

    public abstract void setComments(String comments);

    public abstract int getTabWidth();

    public abstract void setTabWidth(int tabWidth);

} public class ThrowableHandler {

    public static void openError(final Shell shell, final String message) {
        EclipseUtil.openErrorSyncly(shell, Messages.Plugin_Error_Occurred, message);
    }

    public static boolean handleDesignTimeErr(final Shell shell, final Throwable e) {
        return handleDesignTimeErr(shell, e, null);
    }

    private static boolean result;

    public static boolean handleDesignTimeErr(final Shell shell, final Throwable e, final EeClipper clipper) {
        if (e instanceof EDAMUserException) {
            Display.getDefault().syncExec(new Runnable() {
                @Override
                public void run() {
                    result = new EDAMUserExceptionHandler().handleDesingTime(shell, (EDAMUserException) e, clipper);
                }
            });
            return result;
        } else if (e instanceof OutOfDateException) {
            openError(shell, Messages.bind(Messages.Plugin_OutOfDate, EemoryPlugin.getVersion()));
        } else if (e instanceof TTransportException) {
            if (clipper != null) {
                clipper.setInvalid();
            }
            openError(shell, ExceptionUtils.getRootCauseMessage(e));
        } else {
            openError(shell, ExceptionUtils.getRootCauseMessage(e));
        }
        return false;
    }

    public static IStatus handleJobErr(final Throwable e) {
        return handleJobErr(e, null, null, null);
    }

    public static IStatus handleJobErr(final Throwable e, final ENNote args) {
        return handleJobErr(e, null, args, null);
    }

    public static IStatus handleJobErr(final Throwable e, final EeClipper clipper) {
        return handleJobErr(e, clipper, null, null);
    }

    public static IStatus handleJobErr(final Throwable e, final EeClipper clipper, final ENNote args, final Shell shell) {
        if (e instanceof EDAMNotFoundException) {
            if (args != null) {
                return new EDAMNotFoundHandler(EncryptionUtil.decrypt(IDialogSettingsUtil.get(Constants.PLUGIN_SETTINGS_KEY_TOKEN))).fixNotFoundException((EDAMNotFoundException) e, args);
            }
        } else if (e instanceof EDAMUserException) {
            return new EDAMUserExceptionHandler().handleRuntime(shell, (EDAMUserException) e, clipper);
        } else if (e instanceof OutOfDateException) {
            return LogUtil.error(Messages.bind(Messages.Plugin_OutOfDate, EemoryPlugin.getVersion()));
        } else if (e instanceof TTransportException) {
            if (clipper != null) {
                clipper.setInvalid();
            }
        } else if (e instanceof NoDataFoundException) {
            return LogUtil.warning(ExceptionUtils.getRootCauseMessage(e));
        }
        return LogUtil.error(e);
    }

    public static ExecutionException handleExecErr(final Throwable e) {
        return handleExecErr(e, null);
    }

    public static ExecutionException handleExecErr(final Throwable e, final EeClipper clipper) {
        if (e instanceof OutOfDateException) {
            return new ExecutionException(Messages.bind(Messages.Plugin_OutOfDate, EemoryPlugin.getVersion()));
        } else if (e instanceof TTransportException) {
            if (clipper != null) {
                clipper.setInvalid();
            }
        }
        return new ExecutionException(ExceptionUtils.getRootCauseMessage(e), e);
    }

} public class OAuth {

    private static final String CONSUMER_KEY = "eevernote";
    private static final String CONSUMER_SECRET = "kmLkG5Z1dFnBAam5oqie9NgHqN2zfojd+lg/00GRroU=";

    private final CallbackHandler callback;

    public OAuth() throws Exception {
        callback = new JettyCallback();
        callback.ready();
    }

    public String auth(final Shell shell) throws MalformedURLException, InterruptedException {
        try {
            Class<? extends EvernoteApi> apiClass = EvernoteUtil.brand().scribeOAuthApi();
            OAuthService service = new ServiceBuilder().provider(apiClass).apiKey(CONSUMER_KEY).apiSecret(EncryptionUtil.decrypt(CONSUMER_SECRET)).callback(callback.getCallbackURL()).build();
            Token requestToken = service.getRequestToken();
            String authUrl = service.getAuthorizationUrl(requestToken);
            try {
                PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser().openURL(new URL(authUrl));
            } catch (PartInitException couldNotOpenBrowser) {
                LinkedHashMap<String, String> btns = MapUtil.orderedMap();
                btns.put(Constants.Plugin_OAuth_Copy, Messages.Plugin_OAuth_Copy);
                btns.put(Constants.Plugin_OAuth_Cancel, Messages.Plugin_OAuth_Cancel);

                String opt = new SyncEclipseUtil().openCustomImageTypeWithCustomButtonsSyncly(shell, Messages.Plugin_OAuth_Title, Messages.Plugin_OAuth_DoItManually, new Image(Display.getDefault(), getClass().getClassLoader().getResourceAsStream(Constants.OAUTH_EVERNOTE_TRADEMARK)), btns);
                if (Constants.Plugin_OAuth_Copy.equals(opt)) {
                    ClipboardUtil.copy(authUrl);
                } else {
                    return StringUtils.EMPTY;
                }
            }

            // wait for callback handling
            synchronized (callback) {
                callback.wait(30 * 60 * 1000);// 30 minutes
            }

            String verifierValue = callback.getVerifier();
            if (StringUtils.isBlank(verifierValue)) {
                return StringUtils.EMPTY;
            }
            Verifier verifier = new Verifier(verifierValue);
            Token accessToken = service.getAccessToken(requestToken, verifier);
            return accessToken.getToken();
        } finally {
            callback.done();
        }
    }

} public class ConfigurationsDialog extends TitleAreaDialog {

    private final Shell shell;

    private EeClipper globalClipper;

    private Map<String, ENObject> notebooks; // <Name, Guid|Type|LinkedObject>
    private Map<String, ENNote> notes; // <Name, Guid>
    private List<String> tags;

    private SimpleContentProposalProvider notebookProposalProvider;
    private SimpleContentProposalProvider noteProposalProvider;
    private SimpleContentProposalProvider tagsProposalProvider;

    private Map<String, TextField> fields;
    // <Field Property, <Field Property, Field Value>>
    private Map<String, Map<String, String>> matrix;
    // <Field Property, User Input>
    private Map<String, Boolean> inputMatrix;

    // <Field Property, Hint Message>
    private Map<String, String> hintPropMap;

    private boolean canceled = false;

    public ConfigurationsDialog(final Shell parentShell) {
        super(parentShell);
        shell = parentShell;
        notebooks = MapUtil.map();
        notes = MapUtil.map();
        tags = ListUtil.list();
        globalClipper = EeClipperFactory.getInstance().getEeClipper();
        buildHintPropMap();
    }

    @Override
    public void create() {
        super.create();
        setTitle(Messages.Plugin_Configs_Title);
        setMessage(Messages.Plugin_Configs_Message, IMessageProvider.NONE);
    }

    @Override
    protected void configureShell(final Shell newShell) {
        super.configureShell(newShell);
        newShell.setText(Messages.Plugin_Configs_Shell_Title);
    }

    @Override
    protected void setShellStyle(final int newShellStyle) {
        super.setShellStyle(newShellStyle | SWT.RESIZE);
    }

    @Override
    protected Control createDialogArea(final Composite parent) {
        Composite area = (Composite) super.createDialogArea(parent);
        Composite container = new Composite(area, SWT.NONE);
        // container.setLayoutData(new GridData(GridData.FILL_BOTH));
        container.setLayout(new GridLayout(1, false));
        container.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));

        // ----------------------

        Group groupPref = new Group(container, SWT.NONE);
        groupPref.setText(Messages.Plugin_Configs_Organize);
        groupPref.setLayout(new GridLayout(2, false));
        groupPref.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));

        // ----------------------

        // Auth
        authInProgress();

        final LabelCheckTextField notebookField = createLabelCheckTextField(groupPref, Messages.Plugin_Configs_Notebook);
        notebookField.setTextLimit(EDAMLimits.EDAM_NOTEBOOK_NAME_LEN_MAX);
        addField(PLUGIN_CONFIGS_NOTEBOOK, notebookField);
        fetchNotebooksInProgres();
        notebookProposalProvider = EclipseUtil.enableFilteringContentAssist(notebookField.getTextControl(), notebooks.keySet().toArray(new String[notebooks.size()]));
        notebookField.getTextControl().addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(final FocusEvent event) {
                clearHintText(PLUGIN_CONFIGS_NOTEBOOK);
                String[] nbs = notebooks.keySet().toArray(new String[notebooks.size()]);
                Arrays.sort(nbs);
                notebookProposalProvider.setProposals(nbs);
            }

            @Override
            public void focusLost(final FocusEvent e) {
                showHintText(PLUGIN_CONFIGS_NOTEBOOK, Messages.Plugin_Configs_Notebook_Hint);
            }
        });
        notebookField.getCheckControl().addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent event) {
                if (notebookField.isEditable()) {
                    showHintText(PLUGIN_CONFIGS_NOTEBOOK, Messages.Plugin_Configs_Notebook_Hint);
                }
            }
        });
        restoreSettings(PLUGIN_CONFIGS_NOTEBOOK);

        // ----------------------

        final LabelCheckTextField noteField = createLabelCheckTextField(groupPref, Messages.Plugin_Configs_Note);
        noteField.setTextLimit(EDAMLimits.EDAM_NOTE_TITLE_LEN_MAX);
        addField(PLUGIN_CONFIGS_NOTE, noteField);
        fetchNotesInProgres();
        noteProposalProvider = EclipseUtil.enableFilteringContentAssist(noteField.getTextControl(), notes.keySet().toArray(new String[notes.size()]));
        noteField.getTextControl().addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(final FocusEvent e) {
                clearHintText(PLUGIN_CONFIGS_NOTE);
                if (shouldRefresh(PLUGIN_CONFIGS_NOTE, PLUGIN_CONFIGS_NOTEBOOK)) {
                    final String hotebook = getFieldInput(PLUGIN_CONFIGS_NOTEBOOK);
                    BusyIndicator.showWhile(Display.getDefault(), new Runnable() {
                        @Override
                        public void run() {
                            try {
                                notes = globalClipper.listNotesWithinNotebook(ENNoteImpl.forNotebook(notebooks.get(hotebook)));
                            } catch (Throwable e) {
                                boolean fixed = ThrowableHandler.handleDesignTimeErr(shell, e, globalClipper);
                                if (fixed) {
                                    try {
                                        notes = globalClipper.listNotesWithinNotebook(ENNoteImpl.forNotebook(notebooks.get(hotebook)));
                                    } catch (Exception ignored) {
                                    }
                                }
                            }
                        }
                    });
                }
                String[] ns = notes.keySet().toArray(new String[notes.size()]);
                Arrays.sort(ns);
                noteProposalProvider.setProposals(ns);
            }

            @Override
            public void focusLost(final FocusEvent e) {
                showHintText(PLUGIN_CONFIGS_NOTE, Messages.Plugin_Configs_Note_Hint);
            }
        });
        noteField.getCheckControl().addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent event) {
                if (noteField.isEditable()) {
                    showHintText(PLUGIN_CONFIGS_NOTE, Messages.Plugin_Configs_Note_Hint);
                }
            }
        });
        restoreSettings(PLUGIN_CONFIGS_NOTE);

        // ----------------------

        final LabelCheckTextField tagsField = createLabelCheckTextField(groupPref, Messages.Plugin_Configs_Tags);
        tagsField.setTextLimit(EDAMLimits.EDAM_TAG_NAME_LEN_MAX);
        addField(PLUGIN_CONFIGS_TAGS, tagsField);
        fetchTagsInProgress();
        tagsProposalProvider = EclipseUtil.enableFilteringContentAssist(tagsField.getTextControl(), tags.toArray(new String[tags.size()]), TAGS_SEPARATOR);
        tagsField.getTextControl().addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(final FocusEvent event) {
                clearHintText(PLUGIN_CONFIGS_TAGS);
                String[] tagArray = tags.toArray(new String[tags.size()]);
                Arrays.sort(tagArray);
                tagsProposalProvider.setProposals(tagArray);
            }

            @Override
            public void focusLost(final FocusEvent e) {
                showHintText(PLUGIN_CONFIGS_TAGS, Messages.Plugin_Configs_Tags_Hint);
            }
        });
        tagsField.getCheckControl().addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent event) {
                if (tagsField.isEditable()) {
                    showHintText(PLUGIN_CONFIGS_TAGS, Messages.Plugin_Configs_Tags_Hint);
                }
            }
        });
        restoreSettings(PLUGIN_CONFIGS_TAGS);

        TextField commentsField = createLabelCheckTextField(groupPref, Messages.Plugin_Configs_Comments);
        addField(PLUGIN_CONFIGS_COMMENTS, commentsField);
        restoreSettings(PLUGIN_CONFIGS_COMMENTS);

        // ----------------------

        postCreateDialogArea();

        // ----------------------

        return area;
    }

    private void buildHintPropMap() {
        if (hintPropMap == null) {
            hintPropMap = MapUtil.map();
        }
        hintPropMap.put(PLUGIN_CONFIGS_NOTEBOOK, Messages.Plugin_Configs_Notebook_Hint);
        hintPropMap.put(PLUGIN_CONFIGS_NOTE, Messages.Plugin_Configs_Note_Hint);
        hintPropMap.put(PLUGIN_CONFIGS_TAGS, Messages.Plugin_Configs_Tags_Hint);
    }

    private void authInProgress() {
        if (isCanceled()) {
            return;
        }
        try {
            new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress() {
                @Override
                public void run(final IProgressMonitor monitor) {
                    monitor.beginTask(Messages.Plugin_Configs_Authenticating, 1);
                    try {
                        globalClipper = EeClipperFactory.getInstance().getEeClipper(EncryptionUtil.decrypt(IDialogSettingsUtil.get(PLUGIN_SETTINGS_KEY_TOKEN)), false);
                    } catch (Throwable e) {
                        boolean fixed = ThrowableHandler.handleDesignTimeErr(shell, e, globalClipper);
                        if (fixed) {
                            try {
                                globalClipper = EeClipperFactory.getInstance().getEeClipper(EncryptionUtil.decrypt(IDialogSettingsUtil.get(PLUGIN_SETTINGS_KEY_TOKEN)), false);
                            } catch (Exception ignored) {
                            }
                        }
                    }
                    setCanceled(monitor.isCanceled());
                    monitor.done();
                }
            });
        } catch (Throwable e) {
            ThrowableHandler.handleDesignTimeErr(shell, e);
        }
    }

    private void fetchNotebooksInProgres() {
        if (isCanceled()) {
            return;
        }
        try {
            new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress() {
                @Override
                public void run(final IProgressMonitor monitor) {
                    monitor.beginTask(Messages.Plugin_Configs_FetchingNotebooks, 1);
                    try {
                        notebooks = globalClipper.listNotebooks();
                    } catch (Throwable e) {
                        boolean fixed = ThrowableHandler.handleDesignTimeErr(shell, e, globalClipper);
                        if (fixed) {
                            try {
                                globalClipper = EeClipperFactory.getInstance().getEeClipper(EncryptionUtil.decrypt(IDialogSettingsUtil.get(PLUGIN_SETTINGS_KEY_TOKEN)), false);
                                notebooks = globalClipper.listNotebooks();
                            } catch (Exception ignored) {
                            }
                        }
                    }
                    setCanceled(monitor.isCanceled());
                    monitor.done();
                }
            });
        } catch (Throwable e) {
            ThrowableHandler.handleDesignTimeErr(shell, e);
        }
    }

    private void fetchNotesInProgres() {
        if (isCanceled()) {
            return;
        }
        final String notebook = getFieldInput(PLUGIN_CONFIGS_NOTEBOOK);
        try {
            new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress() {
                @Override
                public void run(final IProgressMonitor monitor) {
                    monitor.beginTask(Messages.Plugin_Configs_FetchingNotes, 1);
                    try {
                        notes = globalClipper.listNotesWithinNotebook(ENNoteImpl.forNotebook(notebooks.get(notebook)));
                    } catch (Throwable e) {
                        boolean fixed = ThrowableHandler.handleDesignTimeErr(shell, e, globalClipper);
                        if (fixed) {
                            try {
                                globalClipper = EeClipperFactory.getInstance().getEeClipper(EncryptionUtil.decrypt(IDialogSettingsUtil.get(PLUGIN_SETTINGS_KEY_TOKEN)), false);
                                notes = globalClipper.listNotesWithinNotebook(ENNoteImpl.forNotebook(notebooks.get(notebook)));
                            } catch (Exception ignored) {
                            }
                        }
                    }
                    setCanceled(monitor.isCanceled());
                    monitor.done();
                }
            });
        } catch (Throwable e) {
            ThrowableHandler.handleDesignTimeErr(shell, e);
        }
    }

    private void fetchTagsInProgress() {
        if (isCanceled()) {
            return;
        }
        try {
            new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress() {
                @Override
                public void run(final IProgressMonitor monitor) {
                    monitor.beginTask(Messages.Plugin_Configs_FetchingTags, 1);
                    try {
                        tags = globalClipper.listTags();
                    } catch (Throwable e) {
                        boolean fixed = ThrowableHandler.handleDesignTimeErr(shell, e, globalClipper);
                        if (fixed) {
                            try {
                                globalClipper = EeClipperFactory.getInstance().getEeClipper(EncryptionUtil.decrypt(IDialogSettingsUtil.get(PLUGIN_SETTINGS_KEY_TOKEN)), false);
                                tags = globalClipper.listTags();
                            } catch (Exception ignored) {
                            }
                        }
                    }
                    setCanceled(monitor.isCanceled());
                    monitor.done();
                }
            });
        } catch (Throwable e) {
            ThrowableHandler.handleDesignTimeErr(shell, e);
        }
    }

    protected void postCreateDialogArea() {
        for (Entry<String, String> e : hintPropMap.entrySet()) {
            showHintText(e.getKey(), e.getValue());
        }

        fieldValueChanged(PLUGIN_CONFIGS_NOTE, PLUGIN_CONFIGS_NOTEBOOK);
    }

    private void showHintText(final String property, final String hintMsg) {
        if (getField(property).isEditable() && StringUtils.isBlank(getFieldValue(property))) {
            getField(property).setForeground(shell.getDisplay().getSystemColor(ColorUtil.SWT_COLOR_GRAY));
            setFieldValue(property, hintMsg);
            setHasInput(property, false);
        } else {
            setHasInput(property, true);
        }
    }

    private void clearHintText(final String property) {
        if (!isHasInput(property)) {
            setFieldValue(property, StringUtils.EMPTY);
            // Sets foreground color to the default system color for this control.
            getField(property).setForeground(null);
        }
    }

    @Override
    protected void createButtonsForButtonBar(final Composite parent) {
        createButton(parent, PLUGIN_CONFIGS_REFRESH_ID, Messages.Plugin_Configs_Refresh, false);
        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
        createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
    }

    @Override
    protected void buttonPressed(final int buttonId) {
        if (buttonId == PLUGIN_CONFIGS_REFRESH_ID) {
            refreshPressed();
        } else {
            super.buttonPressed(buttonId);
        }
    }

    protected void refreshPressed() {
        authInProgress();

        // refresh notebook
        fetchNotebooksInProgres();
        diagnoseNotebook();

        // refresh note
        fetchNotesInProgres();
        diagnoseNote();

        // refresh tags
        fetchTagsInProgress();
    }

    private void diagnoseNotebook() {
        String nbName = getFieldInput(PLUGIN_CONFIGS_NOTEBOOK);
        if (StringUtils.isNotBlank(nbName)) {
            if (StringUtils.equals(nbName, IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_NOTEBOOK, PLUGIN_SETTINGS_KEY_UUID))) {
                // user does not change input, so subject to guid
                if (notebooks.containsValue(ENObjectImpl.forGuid(IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_NOTEBOOK, PLUGIN_SETTINGS_KEY_GUID)))) {
                    // rename case on Evernote
                    String key = MapUtil.getKeyByValue(notebooks, ENObjectImpl.forGuid(IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_NOTEBOOK, PLUGIN_SETTINGS_KEY_GUID)));
                    if (isHasInput(PLUGIN_CONFIGS_NOTEBOOK) && !nbName.equals(key)) {
                        setFieldValue(PLUGIN_CONFIGS_NOTEBOOK, key);
                    }
                } else {
                    // re-creation(delete and create a new one with same name) case, and deletion(the configured notebook has been deleted) case on Evernote
                    // but nothing need to do here, Apply will handle all
                }
            } else {
                // user changed input
                // but nothing need to do here, Apply will handle all
            }
        }
    }

    private void diagnoseNote() {
        String nName = getFieldInput(PLUGIN_CONFIGS_NOTE);
        if (!isOk(nName)) {
            if (!StringUtils.equals(nName, IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_NOTE, PLUGIN_SETTINGS_KEY_UUID))) {
                // user changed input
                refreshGuidByName(nName);
            } else {
                // user does not change input, so subject to guid
                if (notes.containsValue(ENNoteImpl.forGuid(IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_NOTE, PLUGIN_SETTINGS_KEY_GUID)))) { // override equals() of ENNote, assume ENNote equals if guid equals
                    // rename case on Evernote
                    String key = MapUtil.getKeyByValue(notes, ENNoteImpl.forGuid(IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_NOTE, PLUGIN_SETTINGS_KEY_GUID)));
                    if (isHasInput(PLUGIN_CONFIGS_NOTE) && !nName.equals(key)) {
                        setFieldValue(PLUGIN_CONFIGS_NOTE, key);
                    }
                } else {
                    // re-creation(delete and create a new one with same name) case, and deletion(the configured notebook has been deleted) case on Evernote
                    refreshGuidByName(nName);
                }
            }
        }
    }

    // diagnose if everything is fine, nothing need to be changed
    private boolean isOk(final String nName) {
        return StringUtils.isBlank(nName) || notes.containsKey(nName) && (StringUtils.equals(notes.get(nName).getName(), IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_NOTE, PLUGIN_SETTINGS_KEY_NAME)) || StringUtils.isBlank(IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_NOTE, PLUGIN_SETTINGS_KEY_NAME))) && (StringUtils.equals(notes.get(nName).getGuid(), IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_NOTE, PLUGIN_SETTINGS_KEY_GUID)) || StringUtils.isBlank(IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_NOTE, PLUGIN_SETTINGS_KEY_GUID)));
    }

    /*
     * Refresh note related information including UI display by NOTE NAME not
     * uuid. Actually this can be done when Apply button is clicked.
     * 
     * Keeping for 1.0.0 release as already tested, considering deletion in next
     * release.
     * 
     * @param nName uuid of note
     */
    @Deprecated
    private void refreshGuidByName(final String nName) {
        // recreate, delete cases
        ENNote noteFound = EDAMNotFoundHandler.findNote(notes, nName); // NOTICE: pass in uuid here, so should not work for name repetition case
        if (noteFound != null && StringUtils.isNotBlank(noteFound.getGuid())) {
            notes.put(nName, noteFound);
            saveNoteSettings(nName);
        }
    }

    @Deprecated
    private void saveNoteSettings(final String noteValue) {
        ENNote note = notes.get(noteValue);
        setSection(PLUGIN_SETTINGS_SECTION_NOTE, note != null ? note.getName() : null, isFieldEditable(PLUGIN_CONFIGS_NOTE), note != null ? note.getGuid() : null, noteValue);
    }

    @Override
    protected void okPressed() {
        try {
            saveSettings();
        } catch (IOException e) {
            ThrowableHandler.handleDesignTimeErr(shell, e);
        }
        super.okPressed();
    }

    @Override
    protected Point getInitialSize() {
        return new Point(550, 400);
    }

    public static int show(final Shell shell) {
        ConfigurationsDialog dialog = new ConfigurationsDialog(shell);
        return dialog.open();
    }

    private boolean shouldRefresh(final String uniqueKey, final String property) {
        return fieldValueChanged(uniqueKey, property);
    }

    private boolean fieldValueChanged(final String uniqueKey, final String property) {
        if (matrix == null) {
            matrix = MapUtil.map();
        }
        Map<String, String> map = matrix.get(uniqueKey);
        if (map == null) {
            map = MapUtil.map();
            matrix.put(uniqueKey, map);
        }
        String fieldValue = isHasInput(property) ? getFieldValue(property) : StringUtils.EMPTY;
        if (!StringUtil.equalsInLogic(fieldValue, map.get(property))) {
            map.put(property, getFieldValue(property));
            return true;
        }
        return false;
    }

    private void saveSettings() throws IOException {
        diagnoseNotebook();
        String notebookValue = getFieldInput(PLUGIN_CONFIGS_NOTEBOOK);
        ENObject notebook = notebooks.get(notebookValue);
        setSection(PLUGIN_SETTINGS_SECTION_NOTEBOOK, notebook != null ? notebook.getName() : null, isFieldEditable(PLUGIN_CONFIGS_NOTEBOOK), notebook != null ? notebook.getGuid() : null, notebookValue, notebook != null ? notebook.getType().toString() : null);
        if (notebook != null && notebook.getType() == ENObjectType.LINKED) {
            // notebook.getLinkedObject() should NOT be null
            IDialogSettingsUtil.set(PLUGIN_SETTINGS_SECTION_NOTEBOOK, PLUGIN_SETTINGS_KEY_OBJECT, ObjectUtil.serialize(notebook.getLinkedObject()));
        } else {
            IDialogSettingsUtil.set(PLUGIN_SETTINGS_SECTION_NOTEBOOK, PLUGIN_SETTINGS_KEY_OBJECT, null);
        }

        diagnoseNote();
        String noteValue = getFieldInput(PLUGIN_CONFIGS_NOTE);
        ENNote note = notes.get(noteValue);
        setSection(PLUGIN_SETTINGS_SECTION_NOTE, note != null ? note.getName() : null, isFieldEditable(PLUGIN_CONFIGS_NOTE), note != null ? note.getGuid() : null, noteValue);

        String tagsValue = getFieldInput(PLUGIN_CONFIGS_TAGS);
        setSection(PLUGIN_SETTINGS_SECTION_TAGS, tagsValue, isFieldEditable(PLUGIN_CONFIGS_TAGS));

        setSection(PLUGIN_SETTINGS_SECTION_COMMENTS, getFieldInput(PLUGIN_CONFIGS_COMMENTS), isFieldEditable(PLUGIN_CONFIGS_COMMENTS));
    }

    private void restoreSettings(final String label) {
        if (label.equals(PLUGIN_CONFIGS_NOTEBOOK)) {
            editableField(PLUGIN_CONFIGS_NOTEBOOK, IDialogSettingsUtil.getBoolean(PLUGIN_SETTINGS_SECTION_NOTEBOOK, PLUGIN_SETTINGS_KEY_CHECKED));
            String value = IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_NOTEBOOK, PLUGIN_SETTINGS_KEY_UUID);
            if (isFieldEditable(PLUGIN_CONFIGS_NOTEBOOK) && StringUtils.isNotBlank(value)) {
                setFieldValue(PLUGIN_CONFIGS_NOTEBOOK, value);
                setHasInput(PLUGIN_CONFIGS_NOTEBOOK, true);
            }
        } else if (label.equals(PLUGIN_CONFIGS_NOTE)) {
            editableField(PLUGIN_CONFIGS_NOTE, IDialogSettingsUtil.getBoolean(PLUGIN_SETTINGS_SECTION_NOTE, PLUGIN_SETTINGS_KEY_CHECKED));
            String value = IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_NOTE, PLUGIN_SETTINGS_KEY_UUID);
            if (isFieldEditable(PLUGIN_CONFIGS_NOTE) && StringUtils.isNotBlank(value)) {
                setFieldValue(PLUGIN_CONFIGS_NOTE, value);
                setHasInput(PLUGIN_CONFIGS_NOTE, true);
            }
        } else if (label.equals(PLUGIN_CONFIGS_TAGS)) {
            editableField(PLUGIN_CONFIGS_TAGS, IDialogSettingsUtil.getBoolean(PLUGIN_SETTINGS_SECTION_TAGS, PLUGIN_SETTINGS_KEY_CHECKED));
            String value = IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_TAGS, PLUGIN_SETTINGS_KEY_NAME);
            if (isFieldEditable(PLUGIN_CONFIGS_TAGS) && StringUtils.isNotBlank(value)) {
                setFieldValue(PLUGIN_CONFIGS_TAGS, value);
                setHasInput(PLUGIN_CONFIGS_TAGS, true);
            }
        } else if (label.equals(PLUGIN_CONFIGS_COMMENTS)) {
            editableField(PLUGIN_CONFIGS_COMMENTS, IDialogSettingsUtil.getBoolean(PLUGIN_SETTINGS_SECTION_COMMENTS, PLUGIN_SETTINGS_KEY_CHECKED));
            String value = IDialogSettingsUtil.get(PLUGIN_SETTINGS_SECTION_COMMENTS, PLUGIN_SETTINGS_KEY_NAME);
            if (isFieldEditable(PLUGIN_CONFIGS_COMMENTS) && StringUtils.isNotBlank(value)) {
                setFieldValue(PLUGIN_CONFIGS_COMMENTS, value);
            }
        }
    }

    private void setSection(final String sectionName, final String name, final boolean isChecked, final String guid, final String uuid, final String type) {
        setSection(sectionName, name, isChecked, guid, uuid);
        IDialogSettingsUtil.set(sectionName, PLUGIN_SETTINGS_KEY_TYPE, type);
    }

    private void setSection(final String sectionName, final String name, final boolean isChecked, final String guid, final String uuid) {
        setSection(sectionName, name, isChecked, guid);
        IDialogSettingsUtil.set(sectionName, PLUGIN_SETTINGS_KEY_UUID, uuid);
    }

    private void setSection(final String sectionName, final String name, final boolean isChecked, final String guid) {
        setSection(sectionName, name, isChecked);
        IDialogSettingsUtil.set(sectionName, PLUGIN_SETTINGS_KEY_GUID, guid);
    }

    private void setSection(final String sectionName, final String name, final boolean isChecked) {
        IDialogSettingsUtil.set(sectionName, PLUGIN_SETTINGS_KEY_NAME, name);
        IDialogSettingsUtil.set(sectionName, PLUGIN_SETTINGS_KEY_CHECKED, isChecked);
    }

    protected LabelCheckTextField createLabelCheckTextField(final Composite container, final String labelText) {
        final Button button = new Button(container, SWT.CHECK);
        button.setText(labelText + ConstantsUtil.COLON);
        button.setSelection(true);

        final Text text = new Text(container, SWT.BORDER);
        text.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
        text.setEnabled(button.getSelection());

        button.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent e) {
                if (!button.getSelection()) {
                    text.setText(StringUtils.EMPTY);
                }
                text.setEnabled(button.getSelection());
                /*
                 * Workaround for Eclipse Bug 193933: Text is not grayed out
                 * when disabled if custom foreground color is set.
                 * 
                 * This happens on Win 7 and earlier version, not observed on Win 10.
                 */
                text.setBackground(button.getSelection() ? null : shell.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));  // null means the default system color for this control.
            }
        });

        return new LabelCheckTextField(button, text);
    }

    protected boolean isFieldEditable(final String property) {
        TextField f = getField(property);
        return f != null && f.isEditable();
    }

    protected void editableField(final String property, final boolean check) {
        TextField f = getField(property);
        if (f != null) {
            f.setEditable(check);
        }
    }

    protected String getFieldValue(final String property) {
        return getField(property).getValue().trim();
    }

    protected String getFieldInput(final String property) {
        if (hintPropMap.containsKey(property)) {
            return isHasInput(property) ? getFieldValue(property) : StringUtils.EMPTY;
        } else {
            return getFieldValue(property);
        }
    }

    protected void setFieldValue(final String property, final String value) {
        TextField f = getField(property);
        if (f != null) {
            f.setValue(value);
        }
    }

    protected TextField getField(final String property) {
        if (fields == null) {
            return null;
        }
        return fields.get(property);
    }

    protected void addField(final String property, final TextField field) {
        if (fields == null) {
            fields = MapUtil.map();
        }
        fields.put(property, field);
    }

    protected boolean isHasInput(final String property) {
        if (inputMatrix == null) {
            return false;
        }
        Boolean has = inputMatrix.get(property);
        return has == null ? false : has;
    }

    protected void setHasInput(final String property, final boolean hasInput) {
        if (inputMatrix == null) {
            inputMatrix = MapUtil.map();
        }
        inputMatrix.put(property, hasInput);
    }

    public boolean isCanceled() {
        return canceled;
    }

    public void setCanceled(final boolean canceled) {
        this.canceled = canceled;
    }

} public interface ScreenCaptureProcessor {

    public void process(BufferedImage imageCaptured);

} public class SyncQuickOrganizeDialog {

    private final Shell shell;
    private int option = QuickOrganizeDialog.CANCEL;

    public SyncQuickOrganizeDialog(final Shell shell) {
        this.shell = shell;
    }

    public int show() {
        Display.getDefault().syncExec(new Runnable() {
            @Override
            public void run() {
                try {
                    option = QuickOrganizeDialog.show(shell);
                } catch (Exception e) {
                    LogUtil.logError(e);
                }
            }
        });
        return option;
    }

} public class ConstantsUtil {

    public static final String COMMA = ",";
    public static final String COLON = ":";
    public static final String SEMICOLON = ";";
    public static final String DOT = ".";
    public static final String POUND = "#";
    public static final String STAR = "*";
    public static final String MD5 = "MD5";
    public static final String LEFT_PARENTHESIS = "(";
    public static final String RIGHT_PARENTHESIS = ")";
    public static final String LEFT_BRACE = "{";
    public static final String RIGHT_BRACE = "}";
    public static final String LESS_THAN = "<";
    public static final String GREATER_THAN = ">";
    public static final String RIGHT_ANGLE_BRACKET = GREATER_THAN;
    public static final String LEFT_ANGLE_BRACKET = LESS_THAN;
    public static final String IMG_PNG = "png";
    public static final String PLUS = "+";
    public static final String MINUS = "-";
    public static final String EQUAL = "=";
    public static final String EXCLAMATION = "!";
    public static final String DOUBLE_QUOTE = "\"";
    public static final String SINGLE_QUOTE = "'";
    public static String SLASH = "/";
    public static String BACKSLASH = "\\";
    public static String QUESTION_MARK = "?";
    public static final String TAB = "\t";

} public class DateTimeUtil {

    public static String timestamp() {
        // 2014-02-21T18:35:32
        return DateFormatUtils.ISO_DATETIME_FORMAT.format(new Date());
    }

    public static String formatCurrentTime(final String pattern) {
        return DateFormatUtils.format(new Date(), pattern);
    }

} public class EclipseUtil {

    public static List<File> getSelectedFiles(final ExecutionEvent event) throws NoDataFoundException {
        ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event).getActivePage().getSelection();

        final List<File> files = ListUtil.list();

        if (selection instanceof ITextSelection) {
            IEditorPart editorPart = HandlerUtil.getActiveEditor(event);
            if (editorPart == null) {
                throw new NoDataFoundException(Messages.Plugin_Error_NoFile);
            }
            IFile iFile = (IFile) editorPart.getEditorInput().getAdapter(IFile.class);
            if (iFile != null) {
                File file = iFile.getLocation().makeAbsolute().toFile();
                files.add(file);
            } else {
                throw new NoDataFoundException(Messages.Plugin_Error_NoFile);
            }
        } else if (selection instanceof IStructuredSelection) {
            Iterator<?> iterator = ((StructuredSelection) selection).iterator();
            while (iterator.hasNext()) {
                IFile iFile = null;
                Object object = iterator.next();
                if (object instanceof IFile) {
                    iFile = (IFile) object;
                } else if (object instanceof IAdaptable) {
                    IAdaptable adapt = (IAdaptable) object;
                    Object resource = adapt.getAdapter(IResource.class);
                    if (resource instanceof IFile) {
                        iFile = (IFile) resource;
                    }
                }
                if (iFile != null) {
                    File file = iFile.getLocation().makeAbsolute().toFile();
                    files.add(file);
                } else {
                    throw new NoDataFoundException(Messages.Plugin_Error_NoFile);
                }
            }
        }

        return files;
    }

    public static List<List<StyleText>> getSelectedStyleText(final StyledText styledText) {
        Point selection = styledText.getSelection();
        String selectionText = styledText.getSelectionText();
        if (StringUtils.isEmpty(selectionText)) {
            return ListUtil.list();
        }

        int size = 10; // 10 as default value in eclipse, will be overwritten by custom
        String face = StringUtils.EMPTY;
        FontStyle foreStyle = FontStyle.NORMAL;
        FontData[] fontDatas = styledText.getFont().getFontData(); // On Windows, only one FontData will be returned per font. On X however, a Font object may be composed of multiple X fonts.
        if (ArrayUtils.isNotEmpty(fontDatas)) {
            size = fontDatas[0].getHeight();

            try {
                foreStyle = FontStyle.forNumber(fontDatas[0].getStyle());
            } catch (IllegalArgumentException e) {
                foreStyle = FontStyle.NORMAL;
            }
            LogUtil.debug(Messages.bind(Messages.Plugin_Debug_Default_Font_Style, foreStyle));

            List<String> fontFamily = ListUtil.list();
            for (FontData f : fontDatas) {
                if (StringUtils.isNotBlank(f.getName())) {
                    fontFamily.add(f.getName());
                }
            }
            face = StringUtils.join(fontFamily, ConstantsUtil.COMMA);
        }

        List<List<StyleText>> list = ListUtil.list();
        int start = 0;
        while (start >= 0) {
            int end = StringUtil.indexOfAny(selectionText, ArrayUtils.toArray(StringUtil.CRLF, StringUtils.CR, StringUtils.LF), start);

            String line = selectionText.substring(start, end < 0 ? selectionText.length() : end);

            int offset = selection.x + start;
            StyleRange[] ranges = styledText.getStyleRanges(offset, line.length());
            List<StyleText> textRanges = parseLine(line, ranges, offset, face, String.valueOf(size), ObjectUtils.defaultIfNull(styledText.getForeground(), ColorUtil.SWT_COLOR_DEFAULT), foreStyle);
            list.add(textRanges);

            start = end < 0 ? end : end + (selectionText.startsWith(StringUtil.CRLF, end) ? StringUtil.CRLF.length() : selectionText.startsWith(StringUtils.CR, end) ? StringUtils.CR.length() : StringUtils.LF.length());
        }

        return list;
    }

    // [PlainText][StyledText][PlainText]
    private static List<StyleText> parseLine(final String text, final StyleRange[] styleRanges, final int offset, final String face, final String size, final Color defaultForeColor, final FontStyle defaultForeStyle) {
        List<StyleText> textRanges = ListUtil.list();

        if (ArrayUtils.isEmpty(styleRanges)) {
            StyleText textRange = new StyleText(text, face, ColorUtil.toHexCode(defaultForeColor.getRed(), defaultForeColor.getGreen(), defaultForeColor.getBlue()), size, defaultForeStyle);
            textRanges.add(textRange);
            return textRanges;
        }

        int count = 0;
        for (StyleRange styleRange : styleRanges) {
            int start = styleRange.start - offset;

            // [PlainText] - Part1
            String part = text.substring(count, start);
            if (!StringUtils.isEmpty(part)) {
                StyleText textRange = new StyleText(part, face, ColorUtil.toHexCode(defaultForeColor.getRed(), defaultForeColor.getGreen(), defaultForeColor.getBlue()), size, defaultForeStyle);
                textRanges.add(textRange);
                count += part.length();
            }

            // // [StyledText]
            part = text.substring(start, start + styleRange.length);
            Color foreground = styleRange.foreground != null ? styleRange.foreground : defaultForeColor;
            FontStyle fontStyle;
            try {
                FontStyle rangeStyle = FontStyle.forNumber(styleRange.fontStyle);
                LogUtil.debug(Messages.bind(Messages.Plugin_Debug_StyleRange_Font_Style, rangeStyle));

                if (rangeStyle == FontStyle.NORMAL && defaultForeStyle != FontStyle.NORMAL) {
                    fontStyle = defaultForeStyle;
                } else {
                    fontStyle = rangeStyle;
                }
            } catch (IllegalArgumentException e) {
                fontStyle = defaultForeStyle;
            }
            LogUtil.debug(Messages.bind(Messages.Plugin_Debug_FinalConcluded_Font_Style, fontStyle));

            StyleText textRange = new StyleText(part, face, ColorUtil.toHexCode(foreground.getRed(), foreground.getGreen(), foreground.getBlue()), size, fontStyle);
            textRanges.add(textRange);
            count += part.length();
        }
        // [PlainText] - Part2
        String part = text.substring(count);
        if (!StringUtils.isEmpty(part)) {
            StyleText textRange = new StyleText(part, face, ColorUtil.toHexCode(defaultForeColor.getRed(), defaultForeColor.getGreen(), defaultForeColor.getBlue()), size, defaultForeStyle);
            textRanges.add(textRange);
        }

        return textRanges;
    }

    public static boolean isBundleInstalled(final String bundleId) {
        return Platform.getBundle(bundleId) != null;
    }

    public static SimpleContentProposalProvider enableFilteringContentAssist(final Control control, final String[] proposals, final String byOperator) {
        Arrays.sort(proposals);
        ConfigContentProposalProvider contentProposalProvider = new ConfigContentProposalProvider(proposals);
        contentProposalProvider.setFiltering(true);
        contentProposalProvider.setByOperator(byOperator);

        ConfigTextContentAdapter textContentAdapter = new ConfigTextContentAdapter();
        textContentAdapter.setByOperator(byOperator);

        new ContentProposalAdapter(control, textContentAdapter, contentProposalProvider, null, null);

        return contentProposalProvider;
    }

    public static SimpleContentProposalProvider enableFilteringContentAssist(final Control control, final String[] proposals) {
        Arrays.sort(proposals);
        SimpleContentProposalProvider contentProposalProvider = new SimpleContentProposalProvider(proposals);
        contentProposalProvider.setFiltering(true);

        TextContentAdapter textContentAdapter = new TextContentAdapter();

        ContentProposalAdapter contentProposalAdapter = new ContentProposalAdapter(control, textContentAdapter, contentProposalProvider, null, null);
        contentProposalAdapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);

        return contentProposalProvider;
    }

    public static void openErrorSyncly(final Shell shell, final String title, final String message) {
        Display.getDefault().syncExec(new Runnable() {
            @Override
            public void run() {
                MessageDialog.openError(shell, title, message);
            }
        });
    }

    public static String openCustomImageTypeWithCustomButtons(final Shell shell, final String title, final String message, final Image dialogImage, final LinkedHashMap<String, String> buttons) {
        return String.valueOf(openCustomImageTypeWithCustomButtons(shell, title, message, dialogImage, buttons, null, false).get(Constants.returnCode));
    }

    public static Map<String, Object> openCustomImageTypeWithCustomButtons(final Shell shell, final String title, final String message, final Image dialogImage, final LinkedHashMap<String, String> buttons, final String toggleMessage, final boolean defaultToggleState) {
        MessageDialog dialog;

        if (StringUtils.isBlank(toggleMessage)) {
            dialog = new MessageDialog(shell, title, null, message, MessageDialog.NONE, buttons.values().toArray(new String[buttons.size()]), 0) {
                @Override
                public Image getImage() {
                    return dialogImage;
                }
            };
        } else {
            dialog = new MessageDialogWithToggle(shell, title, null, message, MessageDialog.NONE, buttons.values().toArray(new String[buttons.size()]), 0, toggleMessage, defaultToggleState) {
                @Override
                public Image getImage() {
                    return dialogImage;
                }

                @Override
                protected void createButtonsForButtonBar(final Composite parent) {
                    String[] buttonLabels = getButtonLabels();
                    Button[] buttons = new Button[buttonLabels.length];
                    int defaultButtonIndex = getDefaultButtonIndex();

                    for (int i = 0; i < buttonLabels.length; i++) {
                        String label = buttonLabels[i];
                        Button button = createButton(parent, i, label, defaultButtonIndex == i);
                        buttons[i] = button;
                    }

                    setButtons(buttons);
                }
            };
        }

        dialog.open();

        Map<String, Object> map = MapUtil.map();
        map.put(Constants.returnCode, buttons.keySet().toArray()[dialog.getReturnCode()]);
        if (dialog instanceof MessageDialogWithToggle) {
            map.put(Constants.toggleState, ((MessageDialogWithToggle) dialog).getToggleState());
        }

        return map;
    }

    public static String openInformationWithCustomButtons(final Shell shell, final String title, final String message, final LinkedHashMap<String, String> buttons) {
        MessageDialog dialog = new MessageDialog(shell, title, null, message, MessageDialog.INFORMATION, buttons.values().toArray(new String[buttons.size()]), 0);
        dialog.open();
        return (String) buttons.keySet().toArray()[dialog.getReturnCode()];
    }

    public static String openQuestionWithCustomButtons(final Shell shell, final String title, final String message, final LinkedHashMap<String, String> buttons) {
        MessageDialog dialog = new MessageDialog(shell, title, null, message, MessageDialog.QUESTION_WITH_CANCEL, buttons.values().toArray(new String[buttons.size()]), 0);
        dialog.open();
        return (String) buttons.keySet().toArray()[dialog.getReturnCode()];
    }

    public static String openWarningWithCustomButtons(final Shell shell, final String title, final String message, final LinkedHashMap<String, String> buttons) {
        MessageDialog dialog = new MessageDialog(shell, title, null, message, MessageDialog.WARNING, buttons.values().toArray(new String[buttons.size()]), 0);
        dialog.open();
        return (String) buttons.keySet().toArray()[dialog.getReturnCode()];
    }

    public static String openErrorWithCustomButtons(final Shell shell, final String title, final String message, final LinkedHashMap<String, String> buttons) {
        MessageDialog dialog = new MessageDialog(shell, title, null, message, MessageDialog.ERROR, buttons.values().toArray(new String[buttons.size()]), 0);
        dialog.open();
        return (String) buttons.keySet().toArray()[dialog.getReturnCode()];
    }

} public class EncryptionUtil {

    private static BasicTextEncryptor textEncryptor;

    static {
        textEncryptor = new BasicTextEncryptor();
        textEncryptor.setPassword(StringUtils.toEncodedString(Base64.decodeBase64("ZWVtb3J5"), Charset.forName(CharEncoding.UTF_8)));
    }

    public static String encrypt(final String plainText) {
        return textEncryptor.encrypt(plainText);
    }

    public static String decrypt(final String encryptedText) {
        return textEncryptor.decrypt(encryptedText);
    }

} public class FileUtil {

    public static String concatNameOfFiles(final List<File> files) {
        return concatNameOfFilesWithSeparator(files, ConstantsUtil.PLUS);
    }

    public static String concatNameOfFilesWithSeparator(final List<File> files, final String separator) {
        String name = StringUtils.EMPTY;
        for (File f : files) {
            if (StringUtils.isNotBlank(name)) {
                name += separator;
            }
            name += f.getName();
        }
        return name;
    }

    public static String mimeType(final File file) {
        if (MimeUtil.getMimeDetector(Constants.MimeDetector) == null) {
            MimeUtil.registerMimeDetector(Constants.MimeDetector);
        }
        return MimeUtil.getMimeTypes(file).toString();
    }

    public static String bytesToHex(final byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte hashByte : bytes) {
            int intVal = 0xff & hashByte;
            if (intVal < 0x10) {
                sb.append(String.valueOf(0));
            }
            sb.append(Integer.toHexString(intVal));
        }
        return sb.toString();
    }

} public class IDialogSettingsUtil {

    private static IDialogSettings settings = EemoryPlugin.getDefault().getDialogSettings();

    public static String get(final String key) {
        return settings.get(key);
    }

    public static boolean getBoolean(final String key) {
        return settings.getBoolean(key);
    }

    public static void set(final String key, final String value) {
        settings.put(key, value);
    }

    public static void set(final String key, final boolean value) {
        settings.put(key, value);
    }

    public static String get(final String sectionName, final String key) {
        IDialogSettings section = settings.getSection(sectionName);
        return section != null ? section.get(key) : null;
    }

    public static boolean getBoolean(final String sectionName, final String key) {
        IDialogSettings section = settings.getSection(sectionName);
        return section != null && section.getBoolean(key);
    }

    public static void set(final String sectionName, final String key, final String value) {
        IDialogSettings section = getOrCreateSection(sectionName);
        section.put(key, value);
    }

    public static void set(final String sectionName, final String key, final boolean value) {
        IDialogSettings section = getOrCreateSection(sectionName);
        section.put(key, value);
    }

    public static IDialogSettings getOrCreateSection(final String sectionName) {
        IDialogSettings section = settings.getSection(sectionName);
        if (section == null) {
            section = settings.addNewSection(sectionName);
        }
        return section;
    }

} public final class ListUtil {

    public static String[] toStringArray(final Collection<String> list) {
        if (list == null) {
            return null;
        }
        String[] array = new String[list.size()];
        return list.toArray(array);
    }

    public static String[] toStringArray(final List<?> list, final ListStringizer stringizer) {
        if (list == null) {
            return null;
        }
        String[] array = new String[list.size()];
        for (int i = 0; i < list.size(); i++) {
            array[i] = stringizer.element(list.get(i));
        }
        return array;
    }

    public static List<String> toStringList(final List<?> list, final ListStringizer stringizer) {
        if (list == null) {
            return null;
        }
        List<String> strList = list();
        for (int i = 0; i < list.size(); i++) {
            strList.add(stringizer.element(list.get(i)));
        }
        return strList;
    }

    public static Map<String, String> toStringMap(final List<?> list, final MapStringizer stringizer) {
        if (list == null) {
            return null;
        }
        Map<String, String> map = MapUtil.map();
        for (int i = 0; i < list.size(); i++) {
            map.put(stringizer.key(list.get(i)), stringizer.value(list.get(i)));
        }
        return map;
    }

    public static <T> List<T> toList(final T[] array) {
        List<T> l = list(array.length);
        l.addAll(Arrays.asList(array));
        return l;
    }

    public static <T> List<T> list(final int initialCapacity) {
        return new ArrayList<T>(initialCapacity);
    }

    public static <T> List<T> list() {
        return new ArrayList<T>();
    }

    @SafeVarargs
    public static <T> List<T> list(final T... objects) {
        List<T> l = list();
        l.addAll(toList(objects));
        return l;
    }

    public static boolean isNullOrEmptyList(final List<?> list) {
        return list == null || list.size() == 0;
    }

    public static boolean isNullList(final Collection<?> list) {
        return list == null;
    }

    public static <T> boolean isIndexOutOfBounds(final List<T> list, final int index) {
        return isNullList(list) || index >= 0 && index < list.size();
    }

    public static <T> void replace(final List<T> list, final T newElement, final int index) {
        if (!isIndexOutOfBounds(list, index)) {
            list.remove(index);
            list.add(index, newElement);
        }
    }

    public static boolean isEqualList(final List<?> one, final List<?> other) {
        return isEqualList(one, other, false);
    }

    public static boolean isEqualList(final List<?> one, final List<?> other, final boolean compareOrder) {
        if (one == other) {
            return true;
        }
        if (isNullList(one) || isNullList(other)) {
            return false;
        }
        if (one.size() != other.size()) {
            return false;
        }
        if (compareOrder) {
            Iterator<?> iter1 = one.iterator();
            Iterator<?> iter2 = other.iterator();
            while (iter1.hasNext() && iter2.hasNext()) {
                if (!ObjectUtil.isEqualObject(iter1.next(), iter2.next())) {
                    return false;
                }
            }
        } else {
            List<Integer> matchedIndex = ListUtil.list();
            andContinue: for (Object o1 : one) {
                for (int i = 0; i < other.size(); i++) {
                    if (matchedIndex.contains(i)) {
                        continue;
                    }
                    if (ObjectUtil.isEqualObject(o1, other.get(i), compareOrder)) {
                        matchedIndex.add(i);
                        break andContinue;
                    }
                }
                return false;
            }
        }
        return true;
    }

    public static <E> List<E> cloneList(final ArrayList<E> source) {
        return cloneList(source, false);
    }

    public static <E> List<E> cloneList(final ArrayList<E> source, final boolean deep) {
        if (!deep) {
            return ObjectUtils.clone(source);
        }
        if (isNullList(source)) {
            return null;
        }
        List<E> list = list(source.size());
        for (E e : source) {
            list.add(ObjectUtil.cloneObject(e, deep));
        }
        return list;
    }

} public class LogUtil {

    private static final ILog log = EemoryPlugin.getDefault().getLog();

    public static void debug(final String message) {
        String debug = System.getProperty(Constants.PLUGIN_DEBUG_MODE);
        if (BooleanUtils.toBoolean(debug)) {
            logInfo(message);
        }
    }

    public static void logInfo(final Throwable exception) {
        log.log(info(exception));
    }

    public static void logWarning(final Throwable exception) {
        log.log(warning(exception));
    }

    public static void logWarning(final String message, final Throwable exception) {
        log.log(warning(message, exception));
    }

    public static void logCancel(final Throwable exception) {
        log.log(cancel(exception));
    }

    public static void logError(final Throwable exception) {
        log.log(error(exception));
    }

    public static void logInfo(final String message) {
        log.log(info(message));
    }

    public static void logWarning(final String message) {
        log.log(warning(message));
    }

    public static void logCancel(final String message) {
        log.log(cancel(message));
    }

    public static void logError(final String message) {
        log.log(error(message));
    }

    public static IStatus info(final Throwable exception) {
        return new Status(Status.INFO, EemoryPlugin.PLUGIN_ID, ExceptionUtils.getRootCauseMessage(exception), exception);
    }

    public static IStatus warning(final Throwable exception) {
        return new Status(Status.WARNING, EemoryPlugin.PLUGIN_ID, ExceptionUtils.getRootCauseMessage(exception), exception);
    }

    public static IStatus warning(final String message, final Throwable exception) {
        return new Status(Status.WARNING, EemoryPlugin.PLUGIN_ID, message, exception);
    }

    public static IStatus cancel(final Throwable exception) {
        return new Status(Status.CANCEL, EemoryPlugin.PLUGIN_ID, ExceptionUtils.getRootCauseMessage(exception), exception);
    }

    public static IStatus error(final Throwable exception) {
        return new Status(Status.ERROR, EemoryPlugin.PLUGIN_ID, ExceptionUtils.getRootCauseMessage(exception), exception);
    }

    public static IStatus info(final String message) {
        return new Status(Status.INFO, EemoryPlugin.PLUGIN_ID, message);
    }

    public static IStatus warning(final String message) {
        return new Status(Status.WARNING, EemoryPlugin.PLUGIN_ID, message);
    }

    public static IStatus cancel(final String message) {
        return new Status(Status.CANCEL, EemoryPlugin.PLUGIN_ID, message);
    }
    public static IStatus error(final String message) {
        return new Status(Status.ERROR, EemoryPlugin.PLUGIN_ID, message);
    }

    public static IStatus ok() {
        return Status.OK_STATUS;
    }

    public static IStatus cancel() {
        return Status.CANCEL_STATUS;
    }

} public class NumberUtil {

    public static int gtZero(final int sourceValue, final int defaultValue) {
        return sourceValue > 0 ? sourceValue : defaultValue;
    }

} public class ObjectUtil {

    public static boolean isEqualObject(final Object one, final Object other) {
        return isEqualObject(one, other, false);
    }

    public static boolean isEqualObject(final Object one, final Object other, final boolean compareOrder) {
        if (one == other) {
            return true;
        }
        if (one == null || other == null) {
            return false;
        }
        if (one instanceof Map && other instanceof Map) {
            return MapUtil.isEqualList((Map<?, ?>) one, (Map<?, ?>) other);
        }
        if (one instanceof List && other instanceof List) {
            return ListUtil.isEqualList((List<?>) one, (List<?>) other, compareOrder);
        }
        if (one instanceof Object[] && other instanceof Object[]) {
            return ArrayUtil.isEqualArray((Object[]) one, (Object[]) other);
        }
        return one.equals(other);
    }

    public static <T> T cloneObject(final T obj) {
        return cloneObject(obj, false);
    }

    public static <T> T cloneObject(final T obj, final boolean deep) {
        if (!deep) {
            return ObjectUtils.clone(obj);
        }
        if (obj == null) {
            return null;
        }

        Object clone = null;
        if (obj instanceof ArrayList) {
            clone = ListUtil.cloneList((ArrayList<?>) obj, deep);
        } else if (obj instanceof HashMap) {
            clone = MapUtil.cloneMap((HashMap<?, ?>) obj, deep);
        } else if (obj.getClass().isArray()) {
            clone = ArrayUtil.cloneArray((Object[]) obj, deep);
        } else if (!(obj instanceof Cloneable)) {
            clone = cloneCloneNotSupportedObject(obj, deep);
        } else {
            // should not be an Array
            clone = ObjectUtils.clone(obj);
        }

        @SuppressWarnings("unchecked")
        // OK because input is of type T
        final T checkedClone = (T) clone;
        return checkedClone;
    }

    @SuppressWarnings("unchecked")
    protected static <T> T cloneCloneNotSupportedObject(final T obj, final boolean deep) {
        if (obj instanceof String) {
            return obj;
        } else if (obj instanceof Byte) {
            return (T) new Byte((Byte) obj);
        } else if (obj instanceof Short) {
            return (T) new Short((Short) obj);
        } else if (obj instanceof Integer) {
            return (T) new Integer((Integer) obj);
        } else if (obj instanceof Long) {
            return (T) new Long((Long) obj);
        } else if (obj instanceof Float) {
            return (T) new Float((Float) obj);
        } else if (obj instanceof Double) {
            return (T) new Double((Double) obj);
        } else if (obj instanceof Boolean) {
            return (T) new Boolean((Boolean) obj);
        } else if (obj instanceof Character) {
            return (T) new Character((Character) obj);
        }
        return null;
    }

    /*
     * Assume object is serializable.
     */
    public static String serialize(final Object object) {
        if (!(object instanceof Serializable)) {
            throw new SerializationException(Messages.bind(Messages.Throwable_NotSerializable_Message, object));
        }
        byte[] bytes = SerializationUtils.serialize((Serializable) object);
        return new String(Base64.encodeBase64(bytes));
    }

    public static Object deserialize(final String base64SerializedString) {
        byte[] bytes = Base64.decodeBase64(base64SerializedString);
        return SerializationUtils.deserialize(bytes);
    }

    public static String toString(final Object obj) {
        return obj == null ? StringUtils.EMPTY : obj.toString();
    }

}
import static org.lttpp.eemory.Constants.FileNamePartSimpleDateFormat;
import static org.lttpp.eemory.Constants.PLUGIN_COMMAND_ID_CLIP_FILE_TO_EVERNOTE;
import static org.lttpp.eemory.Constants.PLUGIN_COMMAND_ID_CLIP_SCREENSHOT_TO_EVERNOTE;
import static org.lttpp.eemory.Constants.PLUGIN_COMMAND_ID_CLIP_SELECTION_TO_EVERNOTE;
import static org.lttpp.eemory.Constants.PLUGIN_COMMAND_ID_CLIP_TO_EVERNOTE;
import static org.lttpp.eemory.Constants.PLUGIN_COMMAND_ID_CONFIGURATIONS;
import static org.lttpp.eemory.Constants.PLUGIN_COMMAND_PARAM_ID;
import static org.lttpp.eemory.Constants.PLUGIN_SETTINGS_KEY_GUID;
import static org.lttpp.eemory.Constants.PLUGIN_SETTINGS_KEY_NAME;
import static org.lttpp.eemory.Constants.PLUGIN_SETTINGS_KEY_OBJECT;
import static org.lttpp.eemory.Constants.PLUGIN_SETTINGS_KEY_TOKEN;
import static org.lttpp.eemory.Constants.PLUGIN_SETTINGS_KEY_TYPE;
import static org.lttpp.eemory.Constants.PLUGIN_SETTINGS_SECTION_COMMENTS;
import static org.lttpp.eemory.Constants.PLUGIN_SETTINGS_SECTION_NOTE;
import static org.lttpp.eemory.Constants.PLUGIN_SETTINGS_SECTION_NOTEBOOK;
import static org.lttpp.eemory.Constants.PLUGIN_SETTINGS_SECTION_TAGS;
import static org.lttpp.eemory.Constants.TAB_WIDTH;
import static org.lttpp.eemory.Constants.TAGS_SEPARATOR;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.imageio.ImageIO;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.handlers.HandlerUtil;
import org.lttpp.eemory.Messages;
import org.lttpp.eemory.client.EeClipper;
import org.lttpp.eemory.client.EeClipperFactory;
import org.lttpp.eemory.client.impl.model.ENNoteImpl;
import org.lttpp.eemory.client.metadata.ENObjectType;
import org.lttpp.eemory.client.model.ENNote;
import org.lttpp.eemory.exception.NoDataFoundException;
import org.lttpp.eemory.exception.ThrowableHandler;
import org.lttpp.eemory.oauth.OAuth;
import org.lttpp.eemory.ui.BootstrappingDialog;
import org.lttpp.eemory.ui.CaptureView;
import org.lttpp.eemory.ui.ConfigurationsDialog;
import org.lttpp.eemory.ui.QuickOrganizeDialog;
import org.lttpp.eemory.ui.ScreenCaptureProcessor;
import org.lttpp.eemory.ui.SyncQuickOrganizeDialog;
import org.lttpp.eemory.util.ConstantsUtil;
import org.lttpp.eemory.util.DateTimeUtil;
import org.lttpp.eemory.util.EclipseUtil;
import org.lttpp.eemory.util.EncryptionUtil;
import org.lttpp.eemory.util.FileUtil;
import org.lttpp.eemory.util.IDialogSettingsUtil;
import org.lttpp.eemory.util.ListUtil;
import org.lttpp.eemory.util.LogUtil;
import org.lttpp.eemory.util.NumberUtil;
import org.lttpp.eemory.util.ObjectUtil;
package org.lttpp.eemory.handlers;





public class EeHandler extends AbstractHandler implements ScreenCaptureProcessor {

    @Override
    public Object execute(final ExecutionEvent event) throws ExecutionException {
        // check token
        if (StringUtils.isBlank(IDialogSettingsUtil.get(PLUGIN_SETTINGS_KEY_TOKEN))) {
            oauth(event);
            if (StringUtils.isBlank(IDialogSettingsUtil.get(PLUGIN_SETTINGS_KEY_TOKEN))) {
                return null;
            } else {
                boolean confirmed = MessageDialog.openConfirm(HandlerUtil.getActiveShellChecked(event), event.getParameter(PLUGIN_COMMAND_PARAM_ID), Messages.Plugin_OAuth_Confirm);
                if (!confirmed) {
                    return null;
                }
            }
        }
        // clip
        if (event.getCommand().getId().equals(PLUGIN_COMMAND_ID_CONFIGURATIONS)) {
            configurationsClicked(event);
        } else if (event.getCommand().getId().equals(PLUGIN_COMMAND_ID_CLIP_TO_EVERNOTE)) {
            clipSelectionClicked(event);
        } else if (event.getCommand().getId().equals(PLUGIN_COMMAND_ID_CLIP_SELECTION_TO_EVERNOTE)) {
            clipSelectionClicked(event);
        } else if (event.getCommand().getId().equals(PLUGIN_COMMAND_ID_CLIP_FILE_TO_EVERNOTE)) {
            clipFileClicked(event);
        } else if (event.getCommand().getId().equals(PLUGIN_COMMAND_ID_CLIP_SCREENSHOT_TO_EVERNOTE)) {
            clipScreenshotClicked(event);
        }
        return null;
    }

    protected void oauth(final ExecutionEvent event) throws ExecutionException {
        final Shell shell = HandlerUtil.getActiveShellChecked(event);
        if (BootstrappingDialog.show(shell)) {
            try {
                new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress() {
                    @Override
                    public void run(final IProgressMonitor monitor) {
                        monitor.beginTask(Messages.Plugin_OAuth_Waiting, IProgressMonitor.UNKNOWN);
                        try {
                            String token = new OAuth().auth(shell);
                            if (StringUtils.isNotBlank(token)) {
                                IDialogSettingsUtil.set(PLUGIN_SETTINGS_KEY_TOKEN, EncryptionUtil.encrypt(token));
                            }
                        } catch (Throwable e) {
                            ThrowableHandler.handleDesignTimeErr(shell, e);
                        }
                        monitor.done();
                    }
                });
            } catch (Throwable e) {
                throw ThrowableHandler.handleExecErr(e);
            }
        }
    }

    protected void clipFileClicked(final ExecutionEvent event) throws ExecutionException {
        try {
            List<File> attachments = EclipseUtil.getSelectedFiles(event);

            final ENNote args = createENNote();

            int option = QuickOrganizeDialog.show(HandlerUtil.getActiveShellChecked(event));
            if (option == QuickOrganizeDialog.OK) {
                args.adopt(QuickOrganizeDialog.getThis().getQuickSettings());
            } else if (option == QuickOrganizeDialog.CANCEL) {
                return;
            }

            args.setAttachments(attachments);
            if (StringUtils.isBlank(args.getName())) {
                args.setName(FileUtil.concatNameOfFiles(args.getAttachments()));
            }
            args.setTabWidth(TAB_WIDTH);

            Job job = new Job(Messages.Plugin_Runtime_ClipFileToEvernote) {
                @Override
                protected IStatus run(final IProgressMonitor monitor) {
                    monitor.beginTask(Messages.Plugin_Runtime_ClipFileToEvernote, 2);
                    EeClipper clipper = null;
                    try {
                        clipper = EeClipperFactory.getInstance().getEeClipper(EncryptionUtil.decrypt(IDialogSettingsUtil.get(PLUGIN_SETTINGS_KEY_TOKEN)), false);
                        monitor.worked(1);

                        if (monitor.isCanceled()) {
                            return LogUtil.cancel();