public class IconApplication implements ApplicationComponent {

    private static final String TAG = IconApplication.class.getSimpleName();
    private static final Logger LOGGER = Logger.getInstance(TAG);
    private IControllerFactory controllerFactory;

    @NotNull
    @Override
    public String getComponentName() {
        return getClass().getName();
    }

    @Override
    public void initComponent() {
        IconPack androidIcons = null;
        IconPack materialIcons = null;
        try {
            final InputStream bundledIconPackPropertiesFile = ResourceLoader.getBundledResourceStream("icon_packs.properties");
            final Properties bundledIconPackProperties = new Properties();
            bundledIconPackProperties.load(bundledIconPackPropertiesFile);

            final boolean export;
            final File localIconPackPropertiesFile = new File(ResourceLoader.getExportPath(), "icon_packs.properties");
            if (!localIconPackPropertiesFile.exists()) {
                export = true;
            } else {
                final Properties localIconPackProperties = new Properties();
                localIconPackProperties.load(FileUtils.openInputStream(localIconPackPropertiesFile));

                export = Integer.parseInt(bundledIconPackProperties.getProperty("version")) !=
                         Integer.parseInt(localIconPackProperties.getProperty("version"));
            }

            final File contentFile = ResourceLoader.getBundledResource("content.json");
            assert contentFile != null;
            final FileReader fileReader = new FileReader(contentFile);
            final Type listType = new TypeToken<ArrayList<IconPack>>() {}.getType();
            GsonBuilder gsonBuilder = new GsonBuilder();
            gsonBuilder.registerTypeAdapter(Resolution.class, new Resolution.Deserializer());
            final Gson gson = gsonBuilder.create();
            final List<IconPack> iconPacks = gson.fromJson(fileReader, listType);
            androidIcons = iconPacks.get(0);
            materialIcons = iconPacks.get(1);

            if (export) {
                new Task.Modal(null, "Prepare Android Drawable Importer", false) {
                    @Override
                    public void run(@NotNull ProgressIndicator progressIndicator) {
                        progressIndicator.setIndeterminate(true);
                        final File archiveFile = ResourceLoader.getBundledResource("icon_packs.zip");
                        final File bundledResource = ResourceLoader.getBundledResource("icon_packs.properties");
                        final File localResource = new File(ResourceLoader.getExportPath(), "icon_packs.properties");

                        try {
                            assert archiveFile != null;
                            ZipUtil.extract(archiveFile, ResourceLoader.getExportPath(), null, true);
                            assert bundledResource != null;
                            FileUtils.copyFile(bundledResource, localResource);
                        } catch (IOException e) {
                            LOGGER.error(e);
                        }
                    }
                }.queue();
            }
        } catch (Exception e) {
            LOGGER.error(e);
        }

        controllerFactory = new DefaultControllerFactory(androidIcons, materialIcons);
    }

    @Override
    public void disposeComponent() {
        controllerFactory.tearDown();
        controllerFactory = null;
    }

    public IControllerFactory getControllerFactory() {
        return controllerFactory;
    }
} public class BatchScaleImporterController implements IBatchScaleImporterController {

    private Set<BatchScaleImporterObserver> observers;
    private Map<String, List<ImageInformation>> images;
    private Map<String, Resolution> sourceResolutions;
    private List<String> sourceFiles;

    public BatchScaleImporterController() {
        this.observers = new HashSet<BatchScaleImporterObserver>();
        this.images = new HashMap<String, List<ImageInformation>>();
        this.sourceResolutions = new HashMap<String, Resolution>();
        this.sourceFiles = new ArrayList<String>() {
            @Override
            public boolean add(String s) {
                if (contains(s)) {
                    return false;
                }
                return super.add(s);
            }
        };
        notifyUpdated();
    }

    @Override
    public void addObserver(BatchScaleImporterObserver observer) {
        observers.add(observer);
        observer.updated();
    }

    @Override
    public void removeObserver(BatchScaleImporterObserver observer) {
        observers.remove(observer);
    }

    @Override
    public void tearDown() {
        observers.clear();
    }

    @Override
    public void addImage(Resolution sourceResolution, List<ImageInformation> imageInformation) {
        if (imageInformation == null ||
                imageInformation.isEmpty()) {
            return;
        }
        final String sourcePath = imageInformation.get(0).getImageFile().getAbsolutePath();
        images.put(sourcePath, imageInformation);
        sourceFiles.add(sourcePath);
        sourceResolutions.put(sourcePath, sourceResolution);
        notifyUpdated();
    }

    @Override
    public void editImages(Project project, Module module, int[] indices) {
        if (indices.length == 0) {
            return;
        }
        DialogWrapper dialogWrapper;
        if (indices.length == 1){
            final int index = indices[0];
            if (index >= sourceFiles.size() || 0 > index) {
                return;
            }
            final String sourceFile = sourceFiles.get(index);
            final List<ImageInformation> imageInformation = images.get(sourceFile);

            dialogWrapper = new AddItemBatchScaleDialog(project,
                                        module,
                                        this,
                                        sourceResolutions.get(sourceFile),
                                        imageInformation);
        } else {
            final List<String> selectedFiles = new ArrayList<String>();
            for (int index : indices) {
                selectedFiles.add(sourceFiles.get(index));
            }
            final List<List<ImageInformation>> imageInformation = new ArrayList<List<ImageInformation>>();
            final List<Resolution> sourceResolution = new ArrayList<Resolution>();
            for (String selectedFile : selectedFiles) {
                imageInformation.add(images.get(selectedFile));
                sourceResolution.add(sourceResolutions.get(selectedFile));
            }
            dialogWrapper = new EditItemsBatchScaleDialog(project,
                                                          module,
                                                          this,
                                                          selectedFiles,
                                                          sourceResolution,
                                                          imageInformation);
        }
        dialogWrapper.show();
    }

    @Override
    public void removeImages(int[] indices) {
        for (int index : indices) {
            if (index >= sourceFiles.size() ||
                0 > index) {
                return;
            }
            removeImage(sourceFiles.get(index));
        }
    }

    @Override
    public void removeImage(String sourcePath) {
        if (!images.containsKey(sourcePath) &&
            !sourceFiles.contains(sourcePath)) {
            return;
        }
        images.remove(sourcePath);
        sourceFiles.remove(sourcePath);
        sourceResolutions.remove(sourcePath);
        notifyUpdated();
    }

    @Override
    public int getImageCount() {
        return sourceFiles.size();
    }

    @Override
    public ImageInformation getImage(int index) {
        if (index >= sourceFiles.size() ||
            0 > index) {
            return null;
        }
        final List<ImageInformation> imageInformation = images.get(sourceFiles.get(index));
        return imageInformation.get(0);
    }

    @Override
    public List<Resolution> getTargetResolutions(ImageInformation information) {
        final String sourcePath = information.getImageFile().getAbsolutePath();
        if (!images.containsKey(sourcePath)) {
            return new ArrayList<Resolution>();
        }
        final List<ImageInformation> imageInformations = images.get(sourcePath);
        final List<Resolution> resolutions = new ArrayList<Resolution>();
        for (ImageInformation image : imageInformations) {
            resolutions.add(image.getTargetResolution());
        }
        return resolutions;
    }

    @Override
    public RefactoringTask getExportTask(Project project) {
        RefactoringTask task = new RefactoringTask(project);
        for (String sourceFile : sourceFiles) {
            final List<ImageInformation> informationList = images.get(sourceFile);
            for (ImageInformation imageInformation : informationList) {
                task.addImage(imageInformation);
            }
        }
        return task;
    }

    private void notifyUpdated() {
        for (BatchScaleImporterObserver observer : observers) {
            observer.updated();
        }
    }
} public interface AddItemBatchScaleDialogObserver {
    void updated();
} public class AddItemBatchScaleImporterController implements IAddItemBatchScaleImporterController {

    private static final Logger LOGGER = Logger.getInstance(AddItemBatchScaleImporterController.class);
    private Set<AddItemBatchScaleDialogObserver> observers;
    private Set<Resolution> targetResolutions;
    private Resolution sourceResolution;
    private String exportName;
    private File imageFile;
    private int originalImageWidth;
    private int targetWidth;
    private int targetHeight;
    private String exportRoot;
    private ResizeAlgorithm algorithm;
    private String method;
    private float aspectRatio;
    private boolean isNinePatch;
    private Format format;
    private Destination destination;

    public AddItemBatchScaleImporterController(IDefaultsController defaultsController,
                                               String exportRoot,
                                               File file) {
        this.observers = new HashSet<AddItemBatchScaleDialogObserver>();
        this.targetResolutions = defaultsController.getResolutions();
        init(file);

        final String fileName = file.getName();
        exportName = ExportNameUtils.getExportNameFromFilename(fileName);
        sourceResolution = defaultsController.getSourceResolution();
        algorithm = defaultsController.getAlgorithm();
        method = defaultsController.getMethod();
        this.exportRoot = exportRoot;
        isNinePatch = fileName.endsWith(".9.png");
        format = isNinePatch ? Format.PNG : defaultsController.getFormat();
        destination = defaultsController.getDestination();
    }

    public AddItemBatchScaleImporterController(Resolution sourceResolution,
                                               List<ImageInformation> information) {
        this.observers = new HashSet<AddItemBatchScaleDialogObserver>();
        this.targetResolutions = new HashSet<Resolution>();
        for (ImageInformation imageInformation : information) {
            targetResolutions.add(imageInformation.getTargetResolution());
        }
        final ImageInformation baseInformation = information.get(0);
        init(baseInformation.getImageFile());

        this.exportName = baseInformation.getExportName();
        this.sourceResolution = sourceResolution;
        this.algorithm = baseInformation.getAlgorithm();
        this.method = algorithm.getPrettyMethod(baseInformation.getMethod());
        this.exportRoot = baseInformation.getExportPath();
        this.isNinePatch = baseInformation.isNinePatch();
        this.format = baseInformation.getFormat();
        destination = baseInformation.getDestination();

        this.targetHeight = getOriginalTargetSize(sourceResolution, baseInformation.getTargetResolution(), targetHeight, baseInformation.getFactor());
        this.targetWidth = getOriginalTargetSize(sourceResolution, baseInformation.getTargetResolution(), targetWidth, baseInformation.getFactor());
    }

    private void init(File file) {
        try {
            LOGGER.info(String.format("Adding file %s", file));
            BufferedImage image = ImageIO.read(file);
            imageFile = file;
            originalImageWidth = image.getWidth();
            targetWidth = image.getWidth();
            targetHeight = image.getHeight();
            aspectRatio = (float) image.getHeight() / (float) originalImageWidth;
        } catch (Exception e) {
            LOGGER.error(e);
        }
    }

    @Override
    public String getExportName() {
        return exportName;
    }

    @Override
    public String getExportPath() {
        return exportRoot;
    }

    @Override
    public Set<Resolution> getTargetResolutions() {
        return targetResolutions;
    }

    @Override
    public int getTargetWidth() {
        return targetWidth;
    }

    @Override
    public int getTargetHeight() {
        return targetHeight;
    }

    @Override
    public ResizeAlgorithm getAlgorithm() {
        return algorithm;
    }

    @Override
    public String getMethod() {
        return method;
    }

    @Override
    public File getImageFile() {
        return imageFile;
    }

    @Override
    public void setSourceResolution(Resolution resolution) {
        sourceResolution = resolution;
        notifyUpdated();
    }

    @Override
    public Resolution getSourceResolution() {
        return sourceResolution;
    }

    @Override
    public void addTargetResolution(Resolution resolution) {
        if (targetResolutions.contains(resolution)) {
            return;
        }
        targetResolutions.add(resolution);
        notifyUpdated();
    }

    @Override
    public void removeTargetResolution(Resolution resolution) {
        if (!targetResolutions.contains(resolution)) {
            return;
        }
        targetResolutions.remove(resolution);
        notifyUpdated();
    }

    @Override
    public void setTargetHeight(int height) {
        if (targetHeight == height) {
            return;
        }
        targetHeight = height;
        targetWidth = (int) (targetHeight / aspectRatio);
        notifyUpdated();
    }

    @Override
    public void setTargetWidth(int width) {
        if (targetWidth == width) {
            return;
        }
        targetWidth = width;
        targetHeight = (int) (aspectRatio * targetWidth);
        notifyUpdated();
    }

    @Override
    public void setTargetRoot(String path) {
        if (exportRoot.equals(path)) {
            return;
        }
        exportRoot = path;
        notifyUpdated();
    }

    @Override
    public void setExportName(String name) {
        if (exportName.equals(name)) {
            return;
        }
        exportName = name;
        notifyUpdated();
    }

    @Override
    public void setAlgorithm(ResizeAlgorithm algorithm) {
        if (algorithm == this.algorithm) {
            return;
        }
        this.algorithm = algorithm;
        this.method = algorithm.getMethods().get(0);
        notifyUpdated();
    }

    @Override
    public void setMethod(String method) {
        if (Objects.equal(method, this.method)) {
            return;
        }
        this.method = method;
        notifyUpdated();
    }

    @Override
    public List<String> getMethods() {
        return algorithm.getMethods();
    }

    @Override
    public Format getFormat() {
        return format;
    }

    @Override
    public boolean isNinePatch() {
        return isNinePatch;
    }

    @Override
    public void setFormat(Format format) {
        if (this.format == format) {
            return;
        }
        this.format = format;
        notifyUpdated();
    }

    @Override
    public Destination getDestination() {
        return destination;
    }

    @Override
    public void setDestination(Destination destination) {
        if (this.destination == destination) {
            return;
        }
        this.destination = destination;
        notifyUpdated();

    }

    @Override
    public int[] getScaledSize(Resolution resolution) {
        final float scaleFactor = RefactorUtils.getScaleFactor(resolution, sourceResolution);
        return new int[] {(int) (scaleFactor * targetWidth), (int) (scaleFactor * targetHeight)};
    }

    @Override
    public List<ImageInformation> getImageInformation(Project project) {
        final ImageInformation base = ImageInformation.newBuilder()
                                                      .setExportName(exportName)
                                                      .setImageFile(imageFile)
                                                      .setAlgorithm(algorithm)
                                                      .setMethod(algorithm.getMethod(method))
                                                      .setExportPath(exportRoot)
                                                      .setNinePatch(isNinePatch)
                                                      .setFormat(format)
                                                      .setDestination(destination)
                                                      .build();
        final List<ImageInformation> images = new ArrayList<ImageInformation>();
        for (Resolution resolution : targetResolutions) {
            images.add(ImageInformation.newBuilder(base)
                                       .setTargetResolution(resolution)
                                       .setFactor(getRealScaleFactor(resolution))
                                       .build());
        }
        return images;
    }

    @Override
    public List<ImageInformation> getImageInformation(Project project,
                                                      String selectedFile,
                                                      List<ImageInformation> imageInformation,
                                                      Resolution sourceResolution) {
        final ImageInformation base = ImageInformation.newBuilder(imageInformation.get(0))
                                                      .setAlgorithm(algorithm)
                                                      .setMethod(algorithm.getMethod(method))
                                                      .setExportPath(exportRoot)
                                                      .setFormat(format)
                                                      .build();
        final List<ImageInformation> images = new ArrayList<ImageInformation>();
        for (Resolution resolution : targetResolutions) {
            images.add(ImageInformation.newBuilder(base)
                                       .setTargetResolution(resolution)
                                       .setFactor(getRealScaleFactor(resolution))
                                       .build());
        }
        return images;
    }

    private float getRealScaleFactor(Resolution targetResolution) {
        final float resolutionScaleFactor = RefactorUtils.getScaleFactor(targetResolution, sourceResolution);
        final float sizeScaleFactor = (float) targetWidth / (float) originalImageWidth;
        return resolutionScaleFactor * sizeScaleFactor;
    }

    private int getOriginalTargetSize(Resolution sourceResolution, Resolution targetResolution, int size, float factor) {
        final float resolutionScaleFactor = RefactorUtils.getScaleFactor(targetResolution, sourceResolution);
        final float sizeScaleFactor = factor / resolutionScaleFactor;
        return (int) (sizeScaleFactor * size);
    }

    @Override
    public void addObserver(AddItemBatchScaleDialogObserver observer) {
        observers.add(observer);
        notifyUpdated();
    }

    @Override
    public void removeObserver(AddItemBatchScaleDialogObserver observer) {
        observers.remove(observer);
    }

    @Override
    public void tearDown() {
        observers.clear();
    }

    private void notifyUpdated() {
        for (AddItemBatchScaleDialogObserver observer : observers) {
            observer.updated();
        }
    }
} public interface IAddItemBatchScaleImporterController extends IController<AddItemBatchScaleDialogObserver> {
    String getExportName();

    String getExportPath();

    Set<Resolution> getTargetResolutions();

    int getTargetWidth();

    int getTargetHeight();

    ResizeAlgorithm getAlgorithm();

    String getMethod();

    File getImageFile();

    void setSourceResolution(Resolution resolution);

    Resolution getSourceResolution();

    void addTargetResolution(Resolution resolution);

    void removeTargetResolution(Resolution resolution);

    void setTargetHeight(int height);

    void setTargetWidth(int width);

    void setTargetRoot(String path);

    void setExportName(String name);

    void setAlgorithm(ResizeAlgorithm algorithm);

    void setMethod(String method);

	void setFormat(Format format);

	void setDestination(Destination destination);

    List<String> getMethods();

    Format getFormat();

	Destination getDestination();

	boolean isNinePatch();

	int[] getScaledSize(Resolution resolution);

    List<ImageInformation> getImageInformation(Project project);

    List<ImageInformation> getImageInformation(Project project,
                                               String selectedFile,
                                               List<ImageInformation> imageInformation,
                                               Resolution sourceResolution);
} public interface IDefaultsController {
    Set<Resolution> getResolutions();
    void setResolutions(Set<Resolution> resolutions);

    ImageAsset getImageAsset();
    void setImageAsset(ImageAsset imageAsset);

    Resolution getSourceResolution();
    void setSourceResolution(Resolution sourceResolution);

    String getSize();
    void setSize(String size);

    String getColor();
    void setColor(String color);

    ResizeAlgorithm getAlgorithm();
    void setAlgorithm(ResizeAlgorithm algorithm);

    String getMethod();
    void setMethod(String method);

    Format getFormat();
    void setFormat(Format format);

    Destination getDestination();
    void setDestination(Destination destination);

    void restore();
    void tearDown();
} public interface ISettingsController extends IController<SettingsObserver> {
    void saveResRootForProject(String fileUrl);
    VirtualFile getResourceRoot();
    String getResourceRootPath();

    String getLastImageFolder();
    void saveLastImageFolder(String fileUrl);

    void setProject(Project project);

    void saveResolutions(Set<Resolution> resolutions);
    Set<Resolution> getResolutions(Set<Resolution> defaultResolutions);

    void saveSourceResolution(Resolution sourceResolution);
    Resolution getSourceResolution(Resolution defaultSourceResolution);

    void saveAlgorithm(ResizeAlgorithm algorithm);
    ResizeAlgorithm getAlgorithm(ResizeAlgorithm defaultAlgorithm);

    void saveMethod(String method);
    String getMethod(String defaultMethod);

    void saveColor(String color);
    String getColor();

    void saveSize(String size);
    String getSize();

    void saveImageAsset(ImageAsset imageAsset);
    ImageAsset getImageAsset();

    void saveFormat(Format format);
    Format getFormat(Format defaultFormat);

    void saveDestination(Destination destination);
    Destination getDestination(Destination defaultDestination);

} public enum Format {
    JPG,
    PNG,
    XML;

    private static final Format[] NON_VECTOR_VALUES = new Format[] {
        JPG, PNG
    };

    public static Format[] nonVectorValues() {
        return NON_VECTOR_VALUES;
    }
} public class ImageInformation {

    public static final String TARGET_FILE_PATTERN = "%s/%s-%s/%s.%s";
    public static final String TMP_ROOT_DIR = "plugin-images";
    private final File imageFile;
    private final Resolution targetResolution;
    private final float factor;
    private final String exportPath;
    private final Format format;
    private final Destination destination;
    private final String exportName;
    private final boolean ninePatch;
    private final boolean vector;
    private ResizeAlgorithm algorithm;
    private Object method;

    private ImageInformation(File imageFile,
                             Resolution targetResolution,
                             float factor,
                             String exportPath,
                             Format format,
                             Destination destination,
                             String exportName,
                             boolean isNinePatch,
                             boolean isVector,
                             ResizeAlgorithm algorithm,
                             Object method) {
        this.imageFile = imageFile;
        this.targetResolution = targetResolution;
        this.factor = factor;
        this.exportPath = exportPath;
        this.format = format;
        this.destination = destination;
        this.exportName = exportName;
        this.ninePatch = isNinePatch;
        this.vector = isVector;
        this.algorithm = algorithm;
        this.method = method;
    }

    public static Builder newBuilder() {
        return new Builder();
    }

    public static Builder newBuilder(ImageInformation imageInformation) {
        return new Builder(imageInformation);
    }

    public static File getTempDir() {
        return new File(PathManager.getPluginTempPath(), TMP_ROOT_DIR);
    }

    public File getTempImage() {
        return new File(getTempDir(), String.format("%s/%s",
                                                    targetResolution.toString().toLowerCase(Locale.ENGLISH),
                                                    exportName));
    }

    public File getImageFile() {
        return imageFile;
    }

    public Resolution getTargetResolution() {
        return targetResolution;
    }

    public float getFactor() {
        return factor;
    }

    public String getExportPath() {
        return exportPath;
    }

    public String getExportName() {
        return exportName;
    }

    public boolean isNinePatch() {
        return ninePatch;
    }

    public ResizeAlgorithm getAlgorithm() {
        return algorithm;
    }

    public Object getMethod() {
        return method;
    }

    public Format getFormat() {
        return format;
    }

    public Destination getDestination() {
        return destination;
    }

    public File getTargetFile() {
        return new File(String.format(TARGET_FILE_PATTERN,
                                      exportPath,
                                      destination.getFolderName(),
                                      targetResolution.toString().toLowerCase(Locale.ENGLISH),
                                      exportName,
                                      format.toString().toLowerCase()));
    }

    public boolean isVector() {
        return vector;
    }

    public static class Builder {

        private File imageFile = null;
        private String exportPath = null;
        private String exportName = null;
        private float factor = 1f;

        // Optional parameters
        private boolean ninePatch = false;
        private boolean vector = false;
        private Resolution targetResolution = Resolution.XHDPI;
        private ResizeAlgorithm algorithm = DefaultsController.DEFAULT_ALGORITHM;
        private Object method = DefaultsController.DEFAULT_ALGORITHM.getMethod(DefaultsController.DEFAULT_METHOD);
        private Format format = DefaultsController.DEFAULT_FORMAT;
        private Destination destination = DefaultsController.DEFAULT_DESTINATION;

        private Builder() {
        }

        private Builder(ImageInformation imageInformation) {
            this.imageFile = imageInformation.imageFile;
            this.targetResolution = imageInformation.targetResolution;
            this.factor = imageInformation.factor;
            this.exportPath = imageInformation.exportPath;
            this.exportName = imageInformation.exportName;
            this.ninePatch = imageInformation.ninePatch;
            this.vector = imageInformation.vector;
            this.algorithm = imageInformation.algorithm;
            this.method = imageInformation.method;
            this.format = imageInformation.format;
            this.destination = imageInformation.destination;
        }

        public Builder setExportName(String exportName) {
            this.exportName = exportName;
            return this;
        }

        public Builder setExportPath(String exportPath) {
            this.exportPath = exportPath;
            return this;
        }

        public Builder setTargetResolution(Resolution targetResolution) {
            this.targetResolution = targetResolution;
            return this;
        }

        public Builder setFactor(float factor) {
            this.factor = factor;
            return this;
        }

        public Builder setVector(boolean vector) {
            this.vector = vector;
            return this;
        }

        public Builder setNinePatch(boolean ninePatch) {
            this.ninePatch = ninePatch;
            return setFormat(format);
        }

        public Builder setAlgorithm(ResizeAlgorithm algorithm) {
            this.algorithm = algorithm;
            return this;
        }

        public Builder setMethod(Object method) {
            this.method = method;
            return this;
        }

        public Builder setImageFile(File imageFile) {
            this.imageFile = imageFile;
            if (exportName == null) {
                exportName = imageFile.getName();
            }
            return this;
        }

        public Builder setFormat(Format format) {
            this.format = isNinePatch() ? Format.PNG : format;
            return this;
        }

        public Builder setDestination(Destination destination) {
            this.destination = destination;
            return this;
        }

        public ImageInformation build() {
            return new ImageInformation(this.imageFile,
                                        this.targetResolution,
                                        this.factor,
                                        this.exportPath,
                                        this.format,
                                        this.destination,
                                        this.exportName,
                                        this.ninePatch,
                                        this.vector,
                                        this.algorithm,
                                        this.method);
        }

        public File getImageFile() {
            return imageFile;
        }

        public String getExportPath() {
            return exportPath;
        }

        public String getExportName() {
            return exportName;
        }

        public float getFactor() {
            return factor;
        }

        public Resolution getTargetResolution() {
            return targetResolution;
        }

        public boolean isNinePatch() {
            return ninePatch;
        }

        public boolean isVector() {
            return vector;
        }

        public ResizeAlgorithm getAlgorithm() {
            return algorithm;
        }

        public Object getMethod() {
            return method;
        }

        public Format getFormat() {
            return format;
        }
    }
} public enum Resolution {
    LDPI,
    MDPI,
    HDPI,
    XHDPI,
    XXHDPI,
    XXXHDPI,
    TVDPI,
    ANYDPI;

    private static final Resolution[] RESOLUTIONS_WITHOUT_SVG = new Resolution[] {
        LDPI, MDPI, HDPI, XHDPI, XXHDPI, XXXHDPI, TVDPI
    };

    public static Resolution[] nonVectorValues() {
        return RESOLUTIONS_WITHOUT_SVG;
    }

    public static Resolution from(String value) {
        if (TextUtils.isEmpty(value)) {
            throw new IllegalArgumentException();
        }
        if (value.equalsIgnoreCase(LDPI.toString())) {
            return LDPI;
        } else if (value.equalsIgnoreCase(MDPI.toString())) {
            return MDPI;
        } else if (value.equalsIgnoreCase(HDPI.toString())) {
            return HDPI;
        } else if (value.equalsIgnoreCase(XHDPI.toString())) {
            return XHDPI;
        } else if (value.equalsIgnoreCase(XXHDPI.toString())) {
            return XXHDPI;
        } else if (value.equalsIgnoreCase(XXXHDPI.toString())) {
            return XXXHDPI;
        } else if (value.equalsIgnoreCase(TVDPI.toString())) {
            return TVDPI;
        } else if (value.equalsIgnoreCase(ANYDPI.toString())) {
            return ANYDPI;
        }
        return null;
    }

    public static class Deserializer implements JsonDeserializer<Resolution> {
        @Override
        public Resolution deserialize(JsonElement jsonElement,
                                  Type type,
                                  JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
            return Resolution.from(jsonElement.getAsString());
        }
    }
} public class FileBrowserField extends TextFieldWithBrowseButton {

    public static final FileChooserDescriptor RESOURCE_DIR_CHOOSER = FileChooserDescriptorFactory.createSingleFolderDescriptor();
    private static final FileType IMAGE_FILE_TYPE = ImageFileTypeManager.getInstance().getImageFileType();
    public static final FileChooserDescriptor IMAGE_FILE_CHOOSER = new FileChooserDescriptor(true,
                                                                                             false,
                                                                                             false,
                                                                                             false,
                                                                                             false,
                                                                                             false) {
        public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
            if (file.isDirectory()) {
                return super.isFileVisible(file, showHiddenFiles);
            }
            return file.getFileType().equals(IMAGE_FILE_TYPE);
        }

        public boolean isFileSelectable(VirtualFile file) {
            if (file.isDirectory()) {
                return super.isFileSelectable(file);
            }
            return super.isFileSelectable(file) && file.getFileType().equals(IMAGE_FILE_TYPE);
        }
    };
    public static final FileChooserDescriptor IMAGE_FILES_FOLDER_CHOOSER = new FileChooserDescriptor(true,
                                                                                                     true,
                                                                                                     false,
                                                                                                     false,
                                                                                                     false,
                                                                                                     true) {
        public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
            if (file.isDirectory()) {
                return super.isFileVisible(file, showHiddenFiles);
            }
            return file.getFileType().equals(IMAGE_FILE_TYPE);
        }

        public boolean isFileSelectable(VirtualFile file) {
            if (file.isDirectory()) {
                return super.isFileSelectable(file);
            }
            return super.isFileSelectable(file) && file.getFileType().equals(IMAGE_FILE_TYPE);
        }
    };

    static {
        RESOURCE_DIR_CHOOSER.setTitle("Select Resource Root");
        IMAGE_FILE_CHOOSER.setTitle("Select Image Asset");
        //noinspection DialogTitleCapitalization
        IMAGE_FILES_FOLDER_CHOOSER.setTitle("Select Image Asset(s)");
    }

    private Project project;
    private ISettingsController settingsController = null;
    private Consumer<File> listener;
    private FileChooserDescriptor descriptor;

    public FileBrowserField(FileChooserDescriptor descriptor) {
        super();
        this.descriptor = descriptor;
        getTextField().setEditable(false);
    }

    public void init(Project project, ISettingsController settingsController) {
        this.project = project;
        this.settingsController = settingsController;
        initFileChooser();
    }

    private void initFileChooser() {
        addBrowseFolderListener(new TextBrowseFolderListener(descriptor) {
            @Override
            protected void onFileChosen(@NotNull VirtualFile chosenFile) {
                super.onFileChosen(chosenFile);
                if (settingsController != null) {
                    settingsController.saveLastImageFolder(chosenFile.getCanonicalPath());
                }
                setText(chosenFile.getCanonicalPath());
            }

            @Nullable
            @Override
            protected Project getProject() {
                return project;
            }

            @Nullable
            @Override
            protected VirtualFile getInitialFile() {
                VirtualFile path = super.getInitialFile();
                if (path != null || settingsController == null) {
                    return path;
                }
                String directoryName = settingsController.getLastImageFolder();
                String expandPath = PathMacroManager.getInstance(project).expandPath(directoryName);
                if (expandPath == null) {
                    return null;
                }
                for (path = LocalFileSystem.getInstance().findFileByPath(expandPath);
                     path == null && directoryName.length() > 0;
                     path = LocalFileSystem.getInstance().findFileByPath(directoryName)) {
                    int pos = directoryName.lastIndexOf(47);
                    if (pos <= 0) {
                        break;
                    }
                    directoryName = directoryName.substring(0, pos);
                }
                return path;
            }
        });
        new FileDrop(getTextField(), new FileDrop.Target() {
            @Override
            public FileChooserDescriptor getDescriptor() {
                return descriptor;
            }

            @Override
            public boolean isHiddenShown() {
                return false;
            }

            @Override
            public void dropFiles(final List<VirtualFile> virtualFiles) {
                if (virtualFiles == null ||
                        virtualFiles.isEmpty()) {
                    return;
                }
                final VirtualFile file = virtualFiles.get(0);
                final String filePath = file.getCanonicalPath();
                settingsController.saveLastImageFolder(filePath);
                setText(filePath);
            }
        });
    }

    public void initWithResourceRoot(Project project, Module module, ISettingsController settings) {
        init(project, settings);
        final VirtualFile resourceDir = settingsController.getResourceRoot();
        if (resourceDir == null) {
            final ResourcesDialog.ResourceSelectionListener listener = new ResourcesDialog.ResourceSelectionListener() {
                @Override
                public void onResourceSelected(VirtualFile resDir) {
                    setText(resDir.getCanonicalPath());
                }
            };
            getResRootFile(this.project, module, listener);
        } else {
            setText(resourceDir.getCanonicalPath());
        }
    }

    private void getResRootFile(Project project, Module module, ResourcesDialog.ResourceSelectionListener listener) {
        final AndroidFacet currentFacet = AndroidFacetUtils.getCurrentFacet(project, module);
        final List<VirtualFile> allResourceDirectories = currentFacet.getAllResourceDirectories();
        if (allResourceDirectories.size() == 1) {
            listener.onResourceSelected(allResourceDirectories.get(0));
        } else if (allResourceDirectories.size() > 1) {
            ResourcesDialog dialog = new ResourcesDialog(project, allResourceDirectories, listener);
            dialog.show();
        }
    }

    @Override
    public void setText(String text) {
        super.setText(text);
        notifyListener(text);
    }

    private void notifyListener(String filePath) {
        if (listener == null || TextUtils.isEmpty(filePath)) {
            return;
        }
        listener.consume(new File(filePath));
    }

    public void setSelectionListener(Consumer<File> fileConsumer) {
        this.listener = fileConsumer;
        notifyListener(getText());
    }
} public class ResolutionButtonModel extends JToggleButton.ToggleButtonModel {

    private Resolution resolution;

    public ResolutionButtonModel(Resolution resolution) {
        this.resolution = resolution;
    }

    public Resolution getResolution() {
        return resolution;
    }
}
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.util.Consumer;
import de.mprengemann.intellij.plugin.androidicons.IconApplication;
import de.mprengemann.intellij.plugin.androidicons.controllers.batchscale.BatchScaleImporterController;
import de.mprengemann.intellij.plugin.androidicons.controllers.batchscale.additem.AddItemBatchScaleDialogObserver;
import de.mprengemann.intellij.plugin.androidicons.controllers.batchscale.additem.AddItemBatchScaleImporterController;
import de.mprengemann.intellij.plugin.androidicons.controllers.batchscale.additem.IAddItemBatchScaleImporterController;
import de.mprengemann.intellij.plugin.androidicons.controllers.defaults.IDefaultsController;
import de.mprengemann.intellij.plugin.androidicons.controllers.settings.ISettingsController;
import de.mprengemann.intellij.plugin.androidicons.images.ResizeAlgorithm;
import de.mprengemann.intellij.plugin.androidicons.listeners.SimpleKeyListener;
import de.mprengemann.intellij.plugin.androidicons.model.Format;
import de.mprengemann.intellij.plugin.androidicons.model.ImageInformation;
import de.mprengemann.intellij.plugin.androidicons.model.Resolution;
import de.mprengemann.intellij.plugin.androidicons.widgets.FileBrowserField;
import de.mprengemann.intellij.plugin.androidicons.widgets.ResolutionButtonModel;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
package de.mprengemann.intellij.plugin.androidicons.dialogs;



public class EditItemsBatchScaleDialog extends DialogWrapper implements AddItemBatchScaleDialogObserver {

    private final Project project;
    private final Module module;
    private final BatchScaleImporterController batchScaleController;
    private final List<String> selectedFiles;
    private List<Resolution> sourceResolution;
    private final List<List<ImageInformation>> information;

    private JPanel uiContainer;
    private JCheckBox LDPICheckBox;
    private JCheckBox MDPICheckBox;
    private JCheckBox HDPICheckBox;
    private JCheckBox XHDPICheckBox;
    private JCheckBox XXHDPICheckBox;
    private JCheckBox XXXHDPICheckBox;
    private JCheckBox TVDPICheckBox;
    private JComboBox sourceResolutionSpinner;
    private FileBrowserField targetRoot;
    private JComboBox algorithmSpinner;
    private JComboBox methodSpinner;
    private JComboBox formatSpinner;
    private IAddItemBatchScaleImporterController controller;
    private final ActionListener sourceResolutionListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent actionEvent) {
            final JComboBox source = (JComboBox) actionEvent.getSource();
            final Resolution selectedItem = (Resolution) source.getSelectedItem();
            controller.setSourceResolution(selectedItem);
        }
    };
    private final ActionListener algorithmListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent actionEvent) {
            final JComboBox source = (JComboBox) actionEvent.getSource();
            final ResizeAlgorithm selectedItem = (ResizeAlgorithm) source.getSelectedItem();
            controller.setAlgorithm(selectedItem);
        }
    };
    private final ActionListener methodListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent actionEvent) {
            final JComboBox source = (JComboBox) actionEvent.getSource();
            final String selectedItem = (String) source.getSelectedItem();
            controller.setMethod(selectedItem);
        }
    };
    private final ActionListener resolutionActionListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent actionEvent) {
            final JCheckBox source = (JCheckBox) actionEvent.getSource();
            final Resolution resolution = ((ResolutionButtonModel) source.getModel()).getResolution();
            if (source.isSelected()) {
                controller.addTargetResolution(resolution);
            } else {
                controller.removeTargetResolution(resolution);
            }
        }
    };
    private final ActionListener formatListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            final JComboBox source = (JComboBox) e.getSource();
            final Format selectedItem = (Format) source.getSelectedItem();
            controller.setFormat(selectedItem);
        }
    };
    private ISettingsController settingsController;
    private IDefaultsController defaultsController;