1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.gallery3d.filtershow.filters;
17
18import android.graphics.Rect;
19import android.util.JsonReader;
20import android.util.JsonWriter;
21
22import com.android.gallery3d.R;
23import com.android.gallery3d.filtershow.editors.EditorGrad;
24import com.android.gallery3d.filtershow.imageshow.MasterImage;
25import com.android.gallery3d.filtershow.imageshow.Line;
26
27import java.io.IOException;
28import java.util.Vector;
29
30public class FilterGradRepresentation extends FilterRepresentation
31        implements Line {
32    private static final String LOGTAG = "FilterGradRepresentation";
33    public static final int MAX_POINTS = 16;
34    public static final int PARAM_BRIGHTNESS = 0;
35    public static final int PARAM_SATURATION = 1;
36    public static final int PARAM_CONTRAST = 2;
37    private static final double ADD_MIN_DIST = .05;
38    private static String LINE_NAME = "Point";
39    private static final  String SERIALIZATION_NAME = "grad";
40
41    public FilterGradRepresentation() {
42        super("Grad");
43        setSerializationName(SERIALIZATION_NAME);
44        creatExample();
45        setOverlayId(R.drawable.filtershow_button_grad);
46        setFilterClass(ImageFilterGrad.class);
47        setTextId(R.string.grad);
48        setEditorId(EditorGrad.ID);
49    }
50
51    public void trimVector(){
52        int n = mBands.size();
53        for (int i = n; i < MAX_POINTS; i++) {
54            mBands.add(new Band());
55        }
56        for (int i = MAX_POINTS; i <  n; i++) {
57            mBands.remove(i);
58        }
59    }
60
61    Vector<Band> mBands = new Vector<Band>();
62    Band mCurrentBand;
63
64    static class Band {
65        private boolean mask = true;
66
67        private int xPos1 = -1;
68        private int yPos1 = 100;
69        private int xPos2 = -1;
70        private int yPos2 = 100;
71        private int brightness = -40;
72        private int contrast = 0;
73        private int saturation = 0;
74
75
76        public Band() {
77        }
78
79        public Band(int x, int y) {
80            xPos1 = x;
81            yPos1 = y+30;
82            xPos2 = x;
83            yPos2 = y-30;
84        }
85
86        public Band(Band copy) {
87            mask = copy.mask;
88            xPos1 = copy.xPos1;
89            yPos1 = copy.yPos1;
90            xPos2 = copy.xPos2;
91            yPos2 = copy.yPos2;
92            brightness = copy.brightness;
93            contrast = copy.contrast;
94            saturation = copy.saturation;
95        }
96
97    }
98
99    @Override
100    public String toString() {
101        int count = 0;
102        for (Band point : mBands) {
103            if (!point.mask) {
104                count++;
105            }
106        }
107        return "c=" + mBands.indexOf(mBands) + "[" + mBands.size() + "]" + count;
108    }
109
110    private void creatExample() {
111        Band p = new Band();
112        p.mask = false;
113        p.xPos1 = -1;
114        p.yPos1 = 100;
115        p.xPos2 = -1;
116        p.yPos2 = 100;
117        p.brightness = -50;
118        p.contrast = 0;
119        p.saturation = 0;
120        mBands.add(0, p);
121        mCurrentBand = p;
122        trimVector();
123    }
124
125    @Override
126    public void useParametersFrom(FilterRepresentation a) {
127            FilterGradRepresentation rep = (FilterGradRepresentation) a;
128            Vector<Band> tmpBands = new Vector<Band>();
129            int n = (rep.mCurrentBand == null) ? 0 : rep.mBands.indexOf(rep.mCurrentBand);
130            for (Band band : rep.mBands) {
131                tmpBands.add(new Band(band));
132            }
133            mCurrentBand = null;
134            mBands = tmpBands;
135            mCurrentBand = mBands.elementAt(n);
136    }
137
138    @Override
139    public FilterRepresentation copy() {
140        FilterGradRepresentation representation = new FilterGradRepresentation();
141        copyAllParameters(representation);
142        return representation;
143    }
144
145    @Override
146    protected void copyAllParameters(FilterRepresentation representation) {
147        super.copyAllParameters(representation);
148        representation.useParametersFrom(this);
149    }
150
151    @Override
152    public boolean equals(FilterRepresentation representation) {
153        if (representation instanceof FilterGradRepresentation) {
154            FilterGradRepresentation rep = (FilterGradRepresentation) representation;
155            int n = getNumberOfBands();
156            if (rep.getNumberOfBands() != n) {
157                return false;
158            }
159            for (int i = 0; i < mBands.size(); i++) {
160                Band b1 = mBands.get(i);
161                Band b2 = rep.mBands.get(i);
162                if (b1.mask != b2.mask
163                        || b1.brightness != b2.brightness
164                        || b1.contrast != b2.contrast
165                        || b1.saturation != b2.saturation
166                        || b1.xPos1 != b2.xPos1
167                        || b1.xPos2 != b2.xPos2
168                        || b1.yPos1 != b2.yPos1
169                        || b1.yPos2 != b2.yPos2) {
170                    return false;
171                }
172            }
173            return true;
174        }
175        return false;
176    }
177
178    public int getNumberOfBands() {
179        int count = 0;
180        for (Band point : mBands) {
181            if (!point.mask) {
182                count++;
183            }
184        }
185        return count;
186    }
187
188    public int addBand(Rect rect) {
189        mBands.add(0, mCurrentBand = new Band(rect.centerX(), rect.centerY()));
190        mCurrentBand.mask = false;
191        int x = (mCurrentBand.xPos1 + mCurrentBand.xPos2)/2;
192        int y = (mCurrentBand.yPos1 + mCurrentBand.yPos2)/2;
193        double addDelta = ADD_MIN_DIST * Math.max(rect.width(), rect.height());
194        boolean moved = true;
195        int count = 0;
196        int toMove =  mBands.indexOf(mCurrentBand);
197
198        while (moved) {
199            moved = false;
200            count++;
201            if (count > 14) {
202                break;
203            }
204
205            for (Band point : mBands) {
206                if (point.mask) {
207                    break;
208                }
209            }
210
211            for (Band point : mBands) {
212                if (point.mask) {
213                    break;
214                }
215                int index = mBands.indexOf(point);
216
217                if (toMove != index) {
218                    double dist = Math.hypot(point.xPos1 - x, point.yPos1 - y);
219                    if (dist < addDelta) {
220                        moved = true;
221                        mCurrentBand.xPos1 += addDelta;
222                        mCurrentBand.yPos1 += addDelta;
223                        mCurrentBand.xPos2 += addDelta;
224                        mCurrentBand.yPos2 += addDelta;
225                        x = (mCurrentBand.xPos1 + mCurrentBand.xPos2)/2;
226                        y = (mCurrentBand.yPos1 + mCurrentBand.yPos2)/2;
227
228                        if (mCurrentBand.yPos1 > rect.bottom) {
229                            mCurrentBand.yPos1 = (int) (rect.top + addDelta);
230                        }
231                        if (mCurrentBand.xPos1 > rect.right) {
232                            mCurrentBand.xPos1 = (int) (rect.left + addDelta);
233                        }
234                    }
235                }
236            }
237        }
238        trimVector();
239        return 0;
240    }
241
242    public void deleteCurrentBand() {
243        int index = mBands.indexOf(mCurrentBand);
244        mBands.remove(mCurrentBand);
245        trimVector();
246        if (getNumberOfBands() == 0) {
247            addBand(MasterImage.getImage().getOriginalBounds());
248        }
249        mCurrentBand = mBands.get(0);
250    }
251
252    public void  nextPoint(){
253        int index = mBands.indexOf(mCurrentBand);
254        int tmp = index;
255        Band point;
256        int k = 0;
257        do  {
258            index =   (index+1)% mBands.size();
259            point = mBands.get(index);
260            if (k++ >= mBands.size()) {
261                break;
262            }
263        }
264        while (point.mask == true);
265        mCurrentBand = mBands.get(index);
266    }
267
268    public void setSelectedPoint(int pos) {
269        mCurrentBand = mBands.get(pos);
270    }
271
272    public int getSelectedPoint() {
273        return mBands.indexOf(mCurrentBand);
274    }
275
276    public boolean[] getMask() {
277        boolean[] ret = new boolean[mBands.size()];
278        int i = 0;
279        for (Band point : mBands) {
280            ret[i++] = !point.mask;
281        }
282        return ret;
283    }
284
285    public int[] getXPos1() {
286        int[] ret = new int[mBands.size()];
287        int i = 0;
288        for (Band point : mBands) {
289            ret[i++] = point.xPos1;
290        }
291        return ret;
292    }
293
294    public int[] getYPos1() {
295        int[] ret = new int[mBands.size()];
296        int i = 0;
297        for (Band point : mBands) {
298            ret[i++] = point.yPos1;
299        }
300        return ret;
301    }
302
303    public int[] getXPos2() {
304        int[] ret = new int[mBands.size()];
305        int i = 0;
306        for (Band point : mBands) {
307            ret[i++] = point.xPos2;
308        }
309        return ret;
310    }
311
312    public int[] getYPos2() {
313        int[] ret = new int[mBands.size()];
314        int i = 0;
315        for (Band point : mBands) {
316            ret[i++] = point.yPos2;
317        }
318        return ret;
319    }
320
321    public int[] getBrightness() {
322        int[] ret = new int[mBands.size()];
323        int i = 0;
324        for (Band point : mBands) {
325            ret[i++] = point.brightness;
326        }
327        return ret;
328    }
329
330    public int[] getContrast() {
331        int[] ret = new int[mBands.size()];
332        int i = 0;
333        for (Band point : mBands) {
334            ret[i++] = point.contrast;
335        }
336        return ret;
337    }
338
339    public int[] getSaturation() {
340        int[] ret = new int[mBands.size()];
341        int i = 0;
342        for (Band point : mBands) {
343            ret[i++] = point.saturation;
344        }
345        return ret;
346    }
347
348    public int getParameter(int type) {
349        switch (type){
350            case PARAM_BRIGHTNESS:
351                return mCurrentBand.brightness;
352            case PARAM_SATURATION:
353                return mCurrentBand.saturation;
354            case PARAM_CONTRAST:
355                return mCurrentBand.contrast;
356        }
357        throw new IllegalArgumentException("no such type " + type);
358    }
359
360    public int getParameterMax(int type) {
361        switch (type) {
362            case PARAM_BRIGHTNESS:
363                return 100;
364            case PARAM_SATURATION:
365                return 100;
366            case PARAM_CONTRAST:
367                return 100;
368        }
369        throw new IllegalArgumentException("no such type " + type);
370    }
371
372    public int getParameterMin(int type) {
373        switch (type) {
374            case PARAM_BRIGHTNESS:
375                return -100;
376            case PARAM_SATURATION:
377                return -100;
378            case PARAM_CONTRAST:
379                return -100;
380        }
381        throw new IllegalArgumentException("no such type " + type);
382    }
383
384    public void setParameter(int type, int value) {
385        mCurrentBand.mask = false;
386        switch (type) {
387            case PARAM_BRIGHTNESS:
388                mCurrentBand.brightness = value;
389                break;
390            case PARAM_SATURATION:
391                mCurrentBand.saturation = value;
392                break;
393            case PARAM_CONTRAST:
394                mCurrentBand.contrast = value;
395                break;
396            default:
397                throw new IllegalArgumentException("no such type " + type);
398        }
399    }
400
401    @Override
402    public void setPoint1(float x, float y) {
403        mCurrentBand.xPos1 = (int)x;
404        mCurrentBand.yPos1 = (int)y;
405    }
406
407    @Override
408    public void setPoint2(float x, float y) {
409        mCurrentBand.xPos2 = (int)x;
410        mCurrentBand.yPos2 = (int)y;
411    }
412
413    @Override
414    public float getPoint1X() {
415        return mCurrentBand.xPos1;
416    }
417
418    @Override
419    public float getPoint1Y() {
420        return mCurrentBand.yPos1;
421    }
422    @Override
423    public float getPoint2X() {
424        return mCurrentBand.xPos2;
425    }
426
427    @Override
428    public float getPoint2Y() {
429        return mCurrentBand.yPos2;
430    }
431
432    @Override
433    public void serializeRepresentation(JsonWriter writer) throws IOException {
434        writer.beginObject();
435        int len = mBands.size();
436        int count = 0;
437
438        for (int i = 0; i < len; i++) {
439            Band point = mBands.get(i);
440            if (point.mask) {
441                continue;
442            }
443            writer.name(LINE_NAME + count);
444            count++;
445            writer.beginArray();
446            writer.value(point.xPos1);
447            writer.value(point.yPos1);
448            writer.value(point.xPos2);
449            writer.value(point.yPos2);
450            writer.value(point.brightness);
451            writer.value(point.contrast);
452            writer.value(point.saturation);
453            writer.endArray();
454        }
455        writer.endObject();
456    }
457
458    @Override
459    public void deSerializeRepresentation(JsonReader sreader) throws IOException {
460        sreader.beginObject();
461        Vector<Band> points = new Vector<Band>();
462
463        while (sreader.hasNext()) {
464            String name = sreader.nextName();
465            if (name.startsWith(LINE_NAME)) {
466                int pointNo = Integer.parseInt(name.substring(LINE_NAME.length()));
467                sreader.beginArray();
468                Band p = new Band();
469                p.mask = false;
470                sreader.hasNext();
471                p.xPos1 = sreader.nextInt();
472                sreader.hasNext();
473                p.yPos1 = sreader.nextInt();
474                sreader.hasNext();
475                p.xPos2 = sreader.nextInt();
476                sreader.hasNext();
477                p.yPos2 = sreader.nextInt();
478                sreader.hasNext();
479                p.brightness = sreader.nextInt();
480                sreader.hasNext();
481                p.contrast = sreader.nextInt();
482                sreader.hasNext();
483                p.saturation = sreader.nextInt();
484                sreader.hasNext();
485                sreader.endArray();
486                points.add(p);
487
488            } else {
489                sreader.skipValue();
490            }
491        }
492        mBands = points;
493        trimVector();
494        mCurrentBand = mBands.get(0);
495        sreader.endObject();
496    }
497}
498