// Export Flex Skins - Photoshop CS3 Script
// Description: Save Flex skins to directory
// Authors: Mark Maguire, Jeff Tranberry
// Version: 2.0, 09/17/2007

/*
@@@BUILDINFO@@@ ExportFlexSkins.jsx 1.0.0.0
*/

//
// ExportFlexSkins.jsx - Export skin files to Flex app directory.
//

/*

// BEGIN__HARVEST_EXCEPTION_ZSTRING

<javascriptresource>
<name>$$$/JavaScripts/ExportFlexSkins/Menu=Export Flex Skins...</name>
<about>$$$/JavaScripts/ExportFlexSkins/About=Export Flex Skins^r^rCopyright 2006-2007 Adobe Systems Incorporated. All rights reserved.^r^rSave Flex skins to directory.</about>
<category>flexskins</category>
</javascriptresource>

// END__HARVEST_EXCEPTION_ZSTRING

*/
// debugging code
/*
debugger;
$.level = 1;
*/

// Set up a variable whether to delete hidden layers
// Could control this through UI if we wanted to
var deleteHidden = true;

// Set up a variable whether to make all hidden layers visible
// Could control this through UI if we wanted to
var allLayersVisible = false;

// on localized builds we pull the $$$/Strings from a .dat file
$.localize = true;

// enable double-clicking from Mac Finder or Windows Explorer
#target photoshop // this command only works in Photoshop CS2 and higher

// bring application forward for double-click events
app.bringToFront();

// globals
// determine Photoshop version number
function getCSVersion() {
	return parseInt(app.version);
}

function getFolder() {
	// display only the browse dialog for Photoshop CS2+
	return Folder.selectDialog(localize("$$$/AdobeFlex/AdobeScripts/Shared/SaveFlexApp/SelectFiles=Please select your Flex Application directory:"), Folder('~'));
}

//////////////
// Functions //
//////////////

function selectAllLayers(){  
   var desc = new ActionDescriptor(); 
        var ref = new ActionReference(); 
        ref.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) ); 
    desc.putReference( charIDToTypeID( "null" ), ref ); 
executeAction( stringIDToTypeID( "selectAllLayers" ), desc, DialogModes.NO ); 
} 

function groupSelectedLayers(){  
    var desc = new ActionDescriptor(); 
        var ref = new ActionReference(); 
        ref.putClass( stringIDToTypeID( "layerSection" ) ); 
    desc.putReference( charIDToTypeID( "null" ), ref ); 
        var ref2 = new ActionReference(); 
        ref2.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) ); 
    desc.putReference( charIDToTypeID( "From" ), ref2 ); 
executeAction(charIDToTypeID( "Mk  " ), desc, DialogModes.NO ); 
}

function ungroupSelectedLayers(){
var id16 = stringIDToTypeID( "ungroupLayersEvent" );
    var desc6 = new ActionDescriptor();
    var id17 = charIDToTypeID( "null" );
        var ref1 = new ActionReference();
        var id18 = charIDToTypeID( "Lyr " );
        var id19 = charIDToTypeID( "Ordn" );
        var id20 = charIDToTypeID( "Trgt" );
        ref1.putEnumerated( id18, id19, id20 );
    desc6.putReference( id17, ref1 );
executeAction( id16, desc6, DialogModes.NO );
}

function hideAllLayers(){
var id8 = charIDToTypeID( "Hd  " );
    var desc3 = new ActionDescriptor();
    var id9 = charIDToTypeID( "null" );
        var list1 = new ActionList();
            var ref1 = new ActionReference();
            var id10 = charIDToTypeID( "Lyr " );
            var id11 = charIDToTypeID( "Ordn" );
            var id12 = charIDToTypeID( "Trgt" );
            ref1.putEnumerated( id10, id11, id12 );
        list1.putReference( ref1 );
    desc3.putList( id9, list1 );
executeAction( id8, desc3, DialogModes.NO );
}

function showLayer(){
var id21 = charIDToTypeID( "Shw " );
    var desc6 = new ActionDescriptor();
    var id22 = charIDToTypeID( "null" );
        var list2 = new ActionList();
            var ref3 = new ActionReference();
            var id23 = charIDToTypeID( "Lyr " );
            var id24 = charIDToTypeID( "Ordn" );
            var id25 = charIDToTypeID( "Trgt" );
            ref3.putEnumerated( id23, id24, id25 );
        list2.putReference( ref3 );
    desc6.putList( id22, list2 );
executeAction( id21, desc6, DialogModes.NO );
}

function duplicateLayer(docName){
var id215 = charIDToTypeID( "Mk  " );
    var desc37 = new ActionDescriptor();
    var id216 = charIDToTypeID( "null" );
        var ref20 = new ActionReference();
        var id217 = charIDToTypeID( "Dcmn" );
        ref20.putClass( id217 );
    desc37.putReference( id216, ref20 );
    var id218 = charIDToTypeID( "Nm  " );
    desc37.putString( id218, docName );
    var id219 = charIDToTypeID( "Usng" );
        var ref21 = new ActionReference();
        var id220 = charIDToTypeID( "Lyr " );
        var id221 = charIDToTypeID( "Ordn" );
        var id222 = charIDToTypeID( "Trgt" );
        ref21.putEnumerated( id220, id221, id222 );
    desc37.putReference( id219, ref21 );
executeAction( id215, desc37, DialogModes.NO );	
}

function s4wPNG(directorypath){
var id41 = charIDToTypeID( "Expr" );
    var desc9 = new ActionDescriptor();
    var id42 = charIDToTypeID( "Usng" );
        var desc10 = new ActionDescriptor();
        var id43 = charIDToTypeID( "Op  " );
        var id44 = charIDToTypeID( "SWOp" );
        var id45 = charIDToTypeID( "OpSa" );
        desc10.putEnumerated( id43, id44, id45 );
        var id46 = charIDToTypeID( "Fmt " );
        var id47 = charIDToTypeID( "IRFm" );
        var id48 = charIDToTypeID( "PN24" );
        desc10.putEnumerated( id46, id47, id48 );
        var id49 = charIDToTypeID( "Intr" );
        desc10.putBoolean( id49, false );
        var id50 = charIDToTypeID( "Trns" );
        desc10.putBoolean( id50, true );
        var id51 = charIDToTypeID( "Mtt " );
        desc10.putBoolean( id51, true );
        var id52 = charIDToTypeID( "MttR" );
        desc10.putInteger( id52, 255 );
        var id53 = charIDToTypeID( "MttG" );
        desc10.putInteger( id53, 255 );
        var id54 = charIDToTypeID( "MttB" );
        desc10.putInteger( id54, 255 );
        var id55 = charIDToTypeID( "SHTM" );
        desc10.putBoolean( id55, false );
        var id56 = charIDToTypeID( "SImg" );
        desc10.putBoolean( id56, true );
        var id57 = charIDToTypeID( "SSSO" );
        desc10.putBoolean( id57, false );
        var id58 = charIDToTypeID( "SSLt" );
            var list3 = new ActionList();
        desc10.putList( id58, list3 );
        var id59 = charIDToTypeID( "DIDr" );
        desc10.putBoolean( id59, false );
        var id60 = charIDToTypeID( "In  " );
        desc10.putPath( id60, new File(directorypath));
    var id61 = stringIDToTypeID( "SaveForWeb" );
    desc9.putObject( id42, id61, desc10 );
executeAction( id41, desc9, DialogModes.NO );
}

function deleteHiddenLayers(){
var id133 = charIDToTypeID( "Dlt " );
    var desc18 = new ActionDescriptor();
    var id134 = charIDToTypeID( "null" );
        var ref7 = new ActionReference();
        var id135 = charIDToTypeID( "Lyr " );
        var id136 = charIDToTypeID( "Ordn" );
        var id137 = stringIDToTypeID( "hidden" );
        ref7.putEnumerated( id135, id136, id137 );
    desc18.putReference( id134, ref7 );
executeAction( id133, desc18, DialogModes.NO );
}

function newLayerFromBackground(){
var id748 = charIDToTypeID( "setd" );
    var desc155 = new ActionDescriptor();
    var id749 = charIDToTypeID( "null" );
        var ref65 = new ActionReference();
        var id750 = charIDToTypeID( "Lyr " );
        var id751 = charIDToTypeID( "Bckg" );
        ref65.putProperty( id750, id751 );
    desc155.putReference( id749, ref65 );
    var id752 = charIDToTypeID( "T   " );
        var desc156 = new ActionDescriptor();
        var id753 = charIDToTypeID( "Opct" );
        var id754 = charIDToTypeID( "#Prc" );
        desc156.putUnitDouble( id753, id754, 100.000000 );
        var id755 = charIDToTypeID( "Md  " );
        var id756 = charIDToTypeID( "BlnM" );
        var id757 = charIDToTypeID( "Nrml" );
        desc156.putEnumerated( id755, id756, id757 );
    var id758 = charIDToTypeID( "Lyr " );
    desc155.putObject( id752, id758, desc156 );
executeAction( id748, desc155, DialogModes.NO );
}

function selectBackLayer(){
var id227 = charIDToTypeID( "slct" );
    var desc46 = new ActionDescriptor();
    var id228 = charIDToTypeID( "null" );
        var ref20 = new ActionReference();
        var id229 = charIDToTypeID( "Lyr " );
        var id230 = charIDToTypeID( "Ordn" );
        var id231 = charIDToTypeID( "Back" );
        ref20.putEnumerated( id229, id230, id231 );
    desc46.putReference( id228, ref20 );
    var id232 = charIDToTypeID( "MkVs" );
    desc46.putBoolean( id232, false );
executeAction( id227, desc46, DialogModes.NO );
}


function unLockLayer(){
	var id81 = charIDToTypeID( "setd" );
    var desc20 = new ActionDescriptor();
    var id82 = charIDToTypeID( "null" );
        var ref17 = new ActionReference();
        var id83 = charIDToTypeID( "Lyr " );
        var id84 = charIDToTypeID( "Ordn" );
        var id85 = charIDToTypeID( "Trgt" );
        ref17.putEnumerated( id83, id84, id85 );
    desc20.putReference( id82, ref17 );
    var id86 = charIDToTypeID( "T   " );
        var desc21 = new ActionDescriptor();
        var id87 = stringIDToTypeID( "layerLocking" );
            var desc22 = new ActionDescriptor();
            var id88 = stringIDToTypeID( "protectNone" );
            desc22.putBoolean( id88, true );
        var id89 = stringIDToTypeID( "layerLocking" );
        desc21.putObject( id87, id89, desc22 );
    var id90 = charIDToTypeID( "Lyr " );
    desc20.putObject( id86, id90, desc21 );
executeAction( id81, desc20, DialogModes.NO );
}

///////////////////////////////////////////////////////////////////////////////
// Function: zeroSuppress
// Usage: return a string padded to digit(s)
// Input: num to convert, digit count needed
// Return: string padded to digit length
///////////////////////////////////////////////////////////////////////////////
function zeroSuppress (num, digit) {
    var tmp = num.toString();
    while (tmp.length < digit) {
		tmp = "0" + tmp;
	}
    return tmp;
}

///////////////////////////////////////////////////////////////////////////////
// Function: setInvisibleAllArtLayers
// Usage: unlock and make invisible all art layers, recursively
// Input: document or layerset
// Return: all art layers are unlocked and invisible
///////////////////////////////////////////////////////////////////////////////
function setInvisibleAllArtLayers(obj) {
    for( var i = 0; i < obj.artLayers.length; i++) {
        obj.artLayers[i].allLocked = false;
        obj.artLayers[i].visible = false;
    }
    for( var i = 0; i < obj.layerSets.length; i++) {
        setInvisibleAllArtLayers(obj.layerSets[i]);
    }
}


///////////////////////////////////////////////////////////////////////////////
// Function: removeAllInvisibleArtLayers
// Usage: remove all the invisible art layers, recursively
// Input: document or layer set
// Return: <none>, all layers that were invisible are now gone
///////////////////////////////////////////////////////////////////////////////
function removeAllInvisibleArtLayers(obj) {
    for( var i = obj.artLayers.length-1; 0 <= i; i--) {
        try {
            if(!obj.artLayers[i].visible) {
				obj.artLayers[i].remove();
			}
        } 
        catch (e) {
        }
    }
    for( var i = obj.layerSets.length-1; 0 <= i; i--) {
        removeAllInvisibleArtLayers(obj.layerSets[i]);
    }
}


///////////////////////////////////////////////////////////////////////////////
// Function: removeAllEmptyLayerSets
// Usage: find all empty layer sets and remove them, recursively
// Input: document or layer set
// Return: empty layer sets are now gone
///////////////////////////////////////////////////////////////////////////////
function removeAllEmptyLayerSets(obj) {
    var foundEmpty = true;
    for( var i = obj.layerSets.length-1; 0 <= i; i--) {
        if( removeAllEmptyLayerSets(obj.layerSets[i])) {
            obj.layerSets[i].remove();
        } else {
            foundEmpty = false;
        }
    }
    if (obj.artLayers.length > 0) {
		foundEmpty = false;
	}
    return foundEmpty;
}

function removeHideBeforeExport(obj) {
    for( var i = obj.layerSets.length-1; 0 <= i; i--) {
        if( obj.layerSets[i].name == "HIDE BEFORE EXPORTING")
            obj.layerSets[i].remove();
    }
}


///////////////////////////////////////////////////////////////////////////////
// Function: removeAllInvisible
// Usage: remove empty and invisible
// Input: document
// Return: void
///////////////////////////////////////////////////////////////////////////////
function removeAllInvisible(docRef) {
    removeAllInvisibleArtLayers(docRef);
    removeAllEmptyLayerSets(docRef);
}

///////////////////////////////////////////////////////////////////////////////
// Function: exportChildren
// Usage: find all the children in this document to save
// Input: duplicate document, original document, export info,
//        reference to document, starting file name
// Return: <none>, documents are saved accordingly
///////////////////////////////////////////////////////////////////////////////
function exportChildren(dupObj, orgObj, dupDocRef, folder) {

if (getCSVersion() >= 10) // CS3 Only
{
	// Create assets folder in Flex app's directory
	var tempFolder;
	tempFolder = new Folder (folder + "/assets/");
	tempFolder.create();

	// try ungrouping the layers 5 times since that's the max depth
	try {
	// Select all the layers
	selectAllLayers();
	// Ungroup them all
	ungroupSelectedLayers();
	ungroupSelectedLayers();
	ungroupSelectedLayers();
	ungroupSelectedLayers();
	ungroupSelectedLayers();
	} catch(e) {
		// ungroupSelectedLayers will bark if there are no more layer groups in the document.
		//alert("You don't have any groups left.");
	}

	// Since all layers are selected at this point,
	// get back to a point where there's only one layer selected.
	// Might as wel be the back most layer.
	selectBackLayer();

	// Iterate through the layers from top to bottom...
	for (var i = 0; i < activeDocument.layers.length; i++) {		
		activeDocument.activeLayer = activeDocument.layers[i];

		//////////////////////////////////////////
		// Put all your processing functions... //
		//////////////////////////////////////////
		
		// Don't export layers that start with an underscore
		if(app.activeDocument.activeLayer.name.substr(0,1) != "_"){
			
			//showLayer();
			
			// Duplicate the current layer to a new document,
			// naming the new documnet after the layers name
			  var fileNameBody = app.activeDocument.activeLayer.name;
				fileNameBody = fileNameBody.replace(/[:\/\\*\?\"\<\>\|]/g, "_");  // '/\:*?"<>|' -> '_'
				if (fileNameBody.length > 120) {
				fileNameBody = fileNameBody.substring(0,120);
			}

			duplicateLayer(fileNameBody);
			
			// Trim the layer to it's smallest bounds by getting rid of any transparent fluff
			app.activeDocument.trim(TrimType.TRANSPARENT,true,true,true,true);
			
			// Use save for web to create the smallest PNG-24
			// Make sure the Output Settings>Saving Files>File Name Compatability is set to allow long file names
			// and saved with the template PSD since we can't control this through scripting!
			s4wPNG(tempFolder + "/");
			
			// Close the duplicated layer/doc
			app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
				
			////////////////////////////////////////////////
			// ...in the area between these two comments. //
			////////////////////////////////////////////////
			
		}

	}
}
else // CS2 and below
{

  }
}


function SaveLayersToFlex(selectedFolder) {

	// if a folder was selected continue with action, otherwise quit
	if (selectedFolder) 
	{
		  
		  if ( app.documents.length <= 0 ) {
        		//alert( strAlertDocumentMustBeOpened );
        		return;
    		  } 		
		    try {
       		 var docName = app.activeDocument.name;  // save the app.activeDocument name before duplicate.

       		 var layerCount = app.documents[docName].layers.length;
       		 var layerSetsCount = app.documents[docName].layerSets.length;


       		 if ((layerCount <= 1)&&(layerSetsCount <= 0)) {
        		    //alert ( strAlertNeedMultipleLayers );
       		 } else {
				
         		   //app.activeDocument = app.documents[docName];
         		   var duppedDocument = app.activeDocument.duplicate();
				   
				   // Start at the top of the layers stack and select each
					// layer in turn
					for (var i = 0; i < activeDocument.layers.length; i++) {		
					activeDocument.activeLayer = activeDocument.layers[i];

						//////////////////////////////////////////
						// Put all your processing functions... //
						//////////////////////////////////////////
						
							// Toss out layersets that start with an underscore, even if they're locked
							if(app.activeDocument.activeLayer.name.substr(0,1) == "_"){
								unLockLayer();
								app.activeDocument.activeLayer.remove();
							}
							
						////////////////////////////////////////////////
						// ...in the area between these two comments. //
						////////////////////////////////////////////////

					}

		         if (getCSVersion() >= 10)
			   {
			   // Look for the bottom-most layer group
			   var myLength = app.activeDocument.layers.length - 1;

			   // Select the bottom-most layer group
			   activeDocument.activeLayer = activeDocument.layers[myLength];

			   // In case this isn't a template document
			   // make sure the background layer is a regular layer so it can be selected via selectAllLayers()
			   if (activeDocument.activeLayer.isBackgroundLayer == true) { //is it anything but a background layer?
				newLayerFromBackground();
				app.activeDocument.activeLayer.name = "Background";
			   }

			   // Delete the bottom-most layer group if it's name is "HIDE BEFORE EXPORTING"
			   removeHideBeforeExport(app.activeDocument);
			   if (app.activeDocument.activeLayer == "HIDE BEFORE EXPORTING"){
				app.activeDocument.activeLayer.remove();
			   }

			   // If we set the flag to true, delete hidden layers
			   if (deleteHidden == true){
			   	try {
					deleteHiddenLayers();
			   	} catch(e) {
					// deleteHiddenLayers will bark if there aren't any hidden layers in the document
			   	}
			   }

			   // If we set the flag to true, show hidden layers
			   if ( allLayersVisible == true){
			    try {
				selectAllLayers();
				showLayer();
			    } catch(e) {
				// showLayer will bark if there aren't any hidden layers in the document
			    }
			   }

			   }
			   else
			   {
			   }
          		   exportChildren(duppedDocument, app.documents[docName], duppedDocument, selectedFolder);
        		   duppedDocument.close( SaveOptions.DONOTSAVECHANGES );
       		 }
    		} catch (e) {
        		alert(e);
    		}

	} else {
		alert(localize("$$$/AdobeDicom/AdobeScripts/Shared/UserCancelled=The action has been cancelled."));
	}
}

if (getCSVersion() >= 10)
{
	SaveLayersToFlex(getFolder());
}
else
{
	alert(localize("$$$/AdobeDicom/AdobeScripts/Shared/NotForCS2=This script is CS3 only"));
}
