def can_load_from_json_file_test(self):
        with open('/Users/scorpio/Dev/Projects/baby-flashcard-app/media/data.json') as json_file:
            image_data = ImageData()
            # json_string = '{ "sets": [ { "id": 1, "name": "domestic" } , { "id": 2, "name": "safari" }   ]}'
            image_data.load_from_json(json_file)

        self.assertEqual(3, len(image_data.deck_sets[0].decks))
    def can_write_image_data_to_json_test(self):
        image_data = ImageData()
        with open('/Users/scorpio/Dev/Projects/baby-flashcard-app/media/data.json') as json_file:
            image_data.load_from_json(json_file)

        json_str = simplejson.dumps(image_data.to_json_dict())

        self.assertTrue(len(json_str) > 50)

        with open('/Users/scorpio/Dev/Projects/baby-flashcard-app/media/data2.json', 'w') as outfile:
            simplejson.dump(image_data.to_json_dict(), outfile, indent=2)
 def __init__(self, media_path):
     self.media_path = media_path
     self.image_data = ImageData()
     self.csv_lines = []
     self.xcassets = {}
     self.xamarin = { "sets": [] }
class CsvCreator:
    data_file_name = 'data2.json'
    csv_file_name= "cropping.csv"
    target_root = '/Users/michaelishmael/Dev/Projects/baby-flashcard-app/media'
    original_root = 'originals'  # '/Users/scorpio/Dev/Projects/baby-flashcard-app/media/originals'
    target_formats = {
         "twelve16": [
            TargetFormat("iphone4", AspectRatio.twelve16, Bounds(0, 0, 960, 640), "iphone", "1x", None),
            TargetFormat("ipad", AspectRatio.twelve16, Bounds(0, 0, 1024, 768), "ipad", "1x", None),
            TargetFormat("ipadretina", AspectRatio.twelve16, Bounds(0, 0, 2048, 1536), "ipad", "2x", "retina4"),
        #     TargetFormat("ipadpro",  CropFormat.twelve16, Bounds(0, 0, 2732, 2048), "ipad", "3x", "retina4"),
         ],
        "nine16": [
            TargetFormat("iphone5", AspectRatio.nine16, Bounds(0, 0, 1138, 640), "iphone", "2x", "retina4"),
            TargetFormat("iphone6", AspectRatio.nine16, Bounds(0, 0, 1334, 750), "iphone", "2x", "retina4"),
            #TargetFormat("iphone6plus", CropFormat.nine16, Bounds(0, 0, 2208, 1242)),
        ]
    }

    def __init__(self, media_path):
        self.media_path = media_path
        self.image_data = ImageData()
        self.csv_lines = []
        self.xcassets = {}
        self.xamarin = { "sets": [] }

    def load(self):
        with open(os.path.join(self.media_path, self.data_file_name)) as json_file:
            self.image_data.load_from_json(json_file)

    def write_csv_lines(self):
        for deck_set in self.image_data.deck_sets:
            set_dict = deck_set.to_json_dict().copy()  # type:dict
            set_dict["decks"] = []
            self.xamarin["sets"].append(set_dict)
            for deck in deck_set.decks:
                deck_dict = deck.to_json_dict().copy()  # type:dict
                deck_dict["cards"] = []
                del deck_dict["sounds"]
                set_dict["decks"].append(deck_dict)

                for card in deck.cards:     # type: FlashCard

                    card_dict = {
                        "id": card.id,
                        "index": card.index,
                        "imagekey": os.path.splitext(card.image)[0],
                        "sound": card.sound,
                        "imagedef": {}
                    }

                    deck_dict["cards"].append(card_dict)

                    for crop_set in card.crop_sets:
                        if crop_set.crop_format == AspectRatio.twelve16:
                            format_key = "twelve16"
                            target_format_list = CsvCreator.target_formats["twelve16"]
                        else:
                            format_key = "nine16"
                            target_format_list = CsvCreator.target_formats["nine16"]

                        for target_format in target_format_list:
                            lines = self.create_csv_lines(target_format, crop_set, card.image, deck.name, deck_set.name, format_key)
                            for line in lines:
                                self.csv_lines.append(line)
                            xcasset_name = os.path.splitext(card.image)[0] + "_" + format_key
                            if len(lines) == 1:
                                self.add_xcasset_image(xcasset_name, lines[0].file_name, target_format)
                                crops = crop_set.get_combined_crops(target_format.target_bounds.long_side(), target_format.target_bounds.short_side())

                                if not card_dict["imagedef"].has_key(format_key):
                                    card_dict["imagedef"][format_key] = {
                                        "imagetype": "combined",
                                        "imageattributes": {
                                            "combinedview": {
                                                "xcassetname": xcasset_name,
                                                "landscapecrop": crops[0].to_json_dict(),
                                                "portraitcrop": crops[1].to_json_dict()
                                            }
                                        }
                                    }
                            elif len(lines) == 2:
                                self.add_xcasset_image(xcasset_name + "_ls", lines[0].file_name, target_format)
                                self.add_xcasset_image(xcasset_name + "_pt", lines[1].file_name, target_format)

                                if not card_dict["imagedef"].has_key(format_key):
                                    card_dict["imagedef"][format_key] = {
                                        "imagetype": "split",
                                        "imageattributes": {
                                            "landscape": {
                                                "xcassetname": xcasset_name + "_ls",
                                            },
                                            "portrait": {
                                                "xcassetname": xcasset_name + "_pt",
                                            }
                                        }
                                    }


    def add_xcasset_image(self, casset_name, image_name, target_format):
        if not self.xcassets.has_key(casset_name):
            self.xcassets[casset_name] = []
        xci = XCassetItem(image_name, target_format.idiom, target_format.scale, target_format.sub_type)
        self.xcassets[casset_name].append(xci)

    def dump_csv_file(self):
        test_line = self.csv_lines[0].to_string()
        ps_path = "/Users/michaelishmael/Dev/Projects/baby-flashcard-app/photoshop/workingtest"
        path = os.path.join(ps_path, self.csv_file_name)
        with open(path, 'w') as csv_file:
            for ln in self.csv_lines:
                csv_file.write(ln.to_string())
                csv_file.write('\n')

    def dump_xcasset_files(self):
        for key in self.xcassets:
            dict_file = {
                "images": [],
                "info": {
                    "version": 1,
                    "author": "xcode"
                }
            }
            for image in self.xcassets[key]:
                dict_file["images"].append(image.to_json_dict())
            path = os.path.join(self.target_root, "xcassets", key + ".imageset", "contents.json")
            if not os.path.exists(os.path.dirname(path)):
                os.makedirs(os.path.dirname(path))
            if os.path.exists(path):
                os.remove(path)
            with open(path, 'w') as json_file:
                simplejson.dump(dict_file, json_file, indent=True)

    def dump_app_json(self):
        path = os.path.join(self.target_root, "appdata.json")
        if not os.path.exists(os.path.dirname(path)):
            os.makedirs(os.path.dirname(path))
        if os.path.exists(path):
            os.remove(path)
        with open(path, 'w') as json_file:
            simplejson.dump(self.xamarin, json_file, indent=True)



    def create_csv_lines(self, target_format, crop_set, image_name, deck_name, set_name, format_key):

        if crop_set.can_be_combined_rect(target_format.target_bounds.long_side(), target_format.target_bounds.short_side()):
            line = self.get_starter_line(target_format, image_name, deck_name, set_name, '_both', format_key)

            crop_percentages = self.get_crop_percentages(crop_set)
            self.set_line_percentages(line, crop_percentages)

            target_size = self.get_crop_size(crop_set, target_format)
            line.target_width = target_size.w
            line.target_height = target_size.h

            return [line]
        else:
            landscape_line = self.get_starter_line(target_format, image_name, deck_name, set_name, '_landscape', format_key)
            self.set_line_percentages(landscape_line, crop_set.landscape_crop_def.percentages)
            landscape_line.target_width = target_format.target_bounds.w
            landscape_line.target_height = target_format.target_bounds.h

            portrait_line = self.get_starter_line(target_format, image_name, deck_name, set_name, '_portrait', format_key)
            self.set_line_percentages(portrait_line, crop_set.portrait_crop_def.percentages)
            portrait_line.target_width = target_format.target_bounds.h
            portrait_line.target_height = target_format.target_bounds.w

            return [landscape_line, portrait_line]


    def get_starter_line(self,target_format, image_name, deck_name, set_name, aspect_suffix, format_key):
        line = CsvRecord()
        line.original_path = os.path.join(CsvCreator.original_root, set_name, deck_name, image_name)
        line.file_name = image_name.replace('.jpg', '_' + target_format.name + aspect_suffix + '.jpg')
        casset_name = os.path.splitext(image_name)[0] + '_' + format_key
        if aspect_suffix == "_landscape":
            casset_name += "_ls"
        if aspect_suffix == "_portrait":
            casset_name += "_pt"
        line.target_path = os.path.join(self.target_root, "xcassets", casset_name + ".imageset", line.file_name)
            #os.path.join(set_name, target_format.folder_path, line.file_name)

        return line

    def set_line_percentages(self, line, crop_percentages):
        line.crop_start_x_pc = crop_percentages[0]
        line.crop_start_y_pc = crop_percentages[1]
        line.crop_end_x_pc = crop_percentages[2]
        line.crop_end_y_pc = crop_percentages[3]

    def get_crop_percentages(self, target_set):
        x = target_set.min_x()
        y = target_set.min_y()
        x2 = target_set.max_x()
        y2 = target_set.max_y()

        return [x, y, x2, y2]

    def get_crop_size(self, target_set, target_format):
        long_side = target_format.target_bounds.w if target_format.target_bounds.w > target_format.target_bounds.h \
            else target_format.target_bounds.h
        short_side = target_format.target_bounds.w if target_format.target_bounds.w < target_format.target_bounds.h \
            else target_format.target_bounds.h

        return target_set.get_new_rect_bounds(long_side, short_side)

    def get_pc_dim_array(self, image_dims, crop_dims):
        pc_x1 = crop_dims.x / image_dims.w
        pc_x2 = crop_dims.x2() / image_dims.w
        pc_y1 = crop_dims.y / image_dims.h
        pc_y2 = crop_dims.y2() / image_dims.h

        return [pc_x1, pc_y1, pc_x2, pc_y2]
 def __init__(self):
     self.image_data = ImageData()
     self.csv_lines = []
     self.data_collector = AppDataCollector()
     self.x_collector = XCassetCollector()
class FileCompiler:
    def __init__(self):
        self.image_data = ImageData()
        self.csv_lines = []
        self.data_collector = AppDataCollector()
        self.x_collector = XCassetCollector()

    def load(self):
        json_file_path = os.path.join(FCS.media_path, FCS.data_file_name)
        with open(json_file_path) as json_file:
            self.image_data.load_from_json(json_file)

    def compile_files(self):
        """

        :type image_key: str
        """
        for deck_set in self.image_data.deck_sets:
            self.data_collector.add_set(deck_set)
            for deck in deck_set.decks:
                self.data_collector.add_deck(deck)

                for card in deck.cards:  # type: FlashCard
                    card_key = os.path.splitext(card.image)[0]

                    self.data_collector.add_card(card)
                    manager = CardFileManager(card_key, card.image)

                    for crop_set in card.crop_sets:  # type: CropSet
                        target_format_list = FCS.target_formats[crop_set.crop_format]

                        for target_format in target_format_list:
                            manager.add_format(target_format, crop_set)

                    src_path_root = os.path.join(FCS.original_root, deck_set.name, deck.name, card.image)
                    lines = manager.get_card_csv_lines(src_path_root, FCS.target_root)

                    for line in lines:
                        self.csv_lines.append(line)

                    x_items = manager.get_xcasset_items(FCS.target_root)
                    for item in x_items:
                        self.x_collector.add_xcasset_image(item)

                    d_images = manager.get_app_image_defs()
                    for key in d_images:
                        self.data_collector.add_image_def(d_images[key])

    def dump_csv_file(self):
        path = os.path.join(FCS.ps_path, FCS.csv_file_name)
        with open(path, 'w') as csv_file:
            for ln in self.csv_lines:
                csv_file.write(ln.to_string())
                csv_file.write('\n')

    def dump_xcasset_files(self):
        self.x_collector.dump_xcasset_files()

    def dump_app_data_json(self):
        self.data_collector.dump_app_json()

    def compile_files_for_card(self, image_key, target_device=None):
        """

        :type image_key: str
        :type target_device: str
        """
        for deck_set in self.image_data.deck_sets:  # type: DeckSet
            if deck_set.contains_card_with_key(image_key):
                self.data_collector.add_set(deck_set)
                for deck in deck_set.decks:  # type: Deck
                    if deck.contains_card_with_key(image_key):
                        self.data_collector.add_deck(deck)

                        for card in deck.cards:  # type: FlashCard
                            card_key = os.path.splitext(card.image)[0]
                            if card_key == image_key:

                                self.data_collector.add_card(card)
                                manager = CardFileManager(card_key, card.image)

                                for crop_set in card.crop_sets:  # type: CropSet
                                    target_format_list = FCS.target_formats[crop_set.crop_format]

                                    for target_format in target_format_list:  # type: TargetFormat
                                        if target_device is None or target_format.name == target_device:
                                            manager.add_format(target_format, crop_set)

                                src_path_root = os.path.join(FCS.original_root, deck_set.name, deck.name, card.image)
                                lines = manager.get_card_csv_lines(src_path_root, FCS.target_root)

                                for line in lines:
                                    self.csv_lines.append(line)

                                #if target_device is None:
                                x_items = manager.get_xcasset_items(FCS.target_root)
                                for item in x_items:
                                    self.x_collector.add_xcasset_image(item)

                                d_images = manager.get_app_image_defs()
                                for key in d_images:
                                    if d_images[key] is not None:
                                        self.data_collector.add_image_def(d_images[key])

    def get_crop_calc(self, image_key, target_device):
        """

        :type image_key: str
        :type target_device: str
        """

        if image_key.endswith(".jpg"):
            image_key = os.path.splitext(image_key)[0]

        self.load()
        self.compile_files_for_card(image_key, target_device)

        line = self.csv_lines[0]  # type:CsvRecord

        crop = {
            "long": line.target_width,
            "short": line.target_height,
            "x1": line.crop_start_x_pc,
            "x2": line.crop_end_x_pc,
            "y1": line.crop_start_y_pc,
            "y2": line.crop_end_y_pc,
        }

        data = self.data_collector.get_data_for_card(image_key, target_device)
        result = {"crop": crop, "def": data}

        return result



    def dump_image(self, image_key):

        """

        :type image_key: str
        """

        if image_key.endswith(".jpg"):
            image_key = os.path.splitext(image_key)[0]

        self.load()
        self.compile_files_for_card(image_key)
        self.data_collector.update_card(image_key)
        self.x_collector.dump_xcasset_files()

        for ln in self.csv_lines:
            nl = ln.to_string()
            as_script = self.get_ascript()
            res = self.as_run(as_script, nl)

    def get_ascript(self):

        ascript = '''
        on run argv
            tell application "Adobe Photoshop CC 2015"
              set js to "#include ~/Dev/Projects/baby-flashcard-app/photoshop/singleImage.jsx" & return
              set js to js & "main(arguments);" & return
              do javascript js with arguments argv

            end tell
        end run
        '''
        return ascript

    def as_run(self, ascript, line):
        "Run the given AppleScript and return the standard output and error."
        home = expanduser("~")
        scpt_path = os.path.join(home, "Dev/Projects/baby-flashcard-app/photoshop/resize_cmd.scpt")
        osa = subprocess.call(
            ['osascript', scpt_path, line])

        # .Popen(['osascript', line],
        #                    stdin=subprocess.PIPE,
        #                    stdout=subprocess.PIPE)
        # res = osa.communicate(ascript)[0]
        # print res, type(osa)
        return osa

    def as_quote(self, astr):
        "Return the AppleScript equivalent of the given string."

        astr = astr.replace('"', '" & quote & "')
        return '"{}"'.format(astr)