# Copyright 2005, @Last Software, Inc.

# This software is provided as an example of using the Ruby interface
# to SketchUp.

# Permission to use, copy, modify, and distribute this software for 
# any purpose and without fee is hereby granted, provided that the above
# copyright notice appear in all copies.

# THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#-----------------------------------------------------------------------------

require 'sketchup.rb'

#-----------------------------------------------------------------------------
# This example shows how you can attach arbitrary attribute data to entities
# and then do queries based on those attributes.

# In this example, there is a method to attach a cost estimate attribute to
# selected faces.  You can then do a query on the model and get the total
# cost estimate.

# This is a global variable that keeps track of the last value entered
$cost_per_sq_ft = 1.00 if not $cost_per_sq_ft

# This method prompts for a cost estimate and attaches it to all selected faces
def attach_cost_estimate

    # See if there is anything selected
    ss = Sketchup.active_model.selection
    return if ss.empty?
    
    # First prompt the user for the cost per sq foot
    prompts = [$exStrings.GetString("Cost per sq. foot")]
    values = [$cost_per_sq_ft]
    results = inputbox prompts, values, $exStrings.GetString("Cost Estimate")
    return if not results
    
    # Now attach this as an attribute to all selected Faces
    $cost_per_sq_ft = results[0]
    ss.each do |e|
        if( e.kind_of? Sketchup::Face )
            # An attributes are stored with named values in a named dictionary
            # In this example, the dictionary name is 'skpex'.
            # The attribute value is named 'cpsf'.
            # Note that you can use any name that you want for the dictionary
            # and the attributes.  The attributes names are currently stored 
            # on every entity that the attribute is attached to however, so
            # it is generally a good idea to keep the name short to avoid
            # using a lot of extra memory storing the attributes.
            e.set_attribute 'skpex', 'cpsf', $cost_per_sq_ft
        end
    end

end

# This method assigns a cost estimate to a Material.  You can then paint
# faces with that material to get them to use that estimate
def assign_estimate_to_material
    # First get a list of all of the materials in the model
    model = Sketchup.active_model
    materials = model.materials
    names = materials.collect {|m| m.name}
    translatednames = materials.collect {|m| m.display_name}
    
    # Display a dialog to pick a material and cost
    prompts = [$exStrings.GetString("Material"), $exStrings.GetString("Cost per sq. foot")]
    values = [translatednames[0], $cost_per_sq_ft]
    enums = [translatednames.join("|")]
    results = inputbox prompts, values, enums, $exStrings.GetString("Cost By Material")
    return if not results
    $cost_per_sq_ft = results[1]
    
    # Get the selected Material
    index = translatednames.index(results[0])
    material = index ? materials[names[index]] : nil
    if( not material )
        UI.messagebox $exStrings.GetString("Could not find Material named") + " #{results[0]}"
        return
    end

    # And attach the cost estimate attribute
    material.set_attribute 'skpex', 'cpsf', $cost_per_sq_ft
end

# This method iterates through all faces in the model and computes the
# total cost estimate based on the the attributes attached to the faces.
# For purposes of this example, it does not look at faces that are inside
# Groups or Components.
def compute_cost_estimate
    total_cost = 0.0
    
    entities = Sketchup.active_model.entities
    entities.each do |e|
        next if not e.kind_of? Sketchup::Face
        
        # See if it has a cost estimate attribute  get_attribute will
        # return nil if there is no attribute matching the given names
        cost_per_sq_ft = e.get_attribute 'skpex', 'cpsf'
        
        # If there is a cost estimate attached directly to the Face
        # then that is used.  Otherwise, look to see if there is a cost
        # estimate attached to a Material for the Face.  This is a little
        # bit of a problem because a Face can have a front and back Material.
        # For this example, we use the cost estimates from both
        if not cost_per_sq_ft
            material = e.material
            if( material )
                cost_per_sq_ft = material.get_attribute 'skpex', 'cpsf'
            end
            material = e.back_material
            if( material )
                cpsf_back = material.get_attribute 'skpex', 'cpsf'
                if( cpsf_back )
                    if( cost_per_sq_ft )
                        cost_per_sq_ft += cpsf_back
                    else
                        cost_per_sq_ft = cpsf_back
                    end
                end
            end
        end
        
        # If there is not Material with a cost estimate on it, then
        # skip this Face.
        next if not cost_per_sq_ft
        
        # Compute the estimate for this face based on the area
        # The area is returned in square inches - convert to square feet
        area = e.area / 144.0
        cost = area * cost_per_sq_ft
        
        total_cost += cost
    end
    
    # Now display the results
    dollars = format("%.2f", total_cost)
    msg = $exStrings.GetString("Total Cost Estimate") + " = \$#{dollars}"
    UI.messagebox(msg, MB_OK, $exStrings.GetString("Cost Estimate"))
end

# Add some menu items to access this
if( not file_loaded?("attributes.rb") )
    plugins_menu = UI.menu($exStrings.GetString("Plugins"))
    cost_menu = plugins_menu.add_submenu($exStrings.GetString("Cost"))
    cost_menu.add_item($exStrings.GetString("Assign Estimate to Material")) { assign_estimate_to_material }
    cost_menu.add_item($exStrings.GetString("Assign Estimate to Faces")) { attach_cost_estimate }
    cost_menu.add_item($exStrings.GetString("Compute Estimate")) { compute_cost_estimate }
end

#-----------------------------------------------------------------------------
file_loaded("attributes.rb")
