module DocxGenerator
  module DSL
    # Represent the docx document.
    class Document
      # Filename of the document (without the docx extension).
      attr_reader :filename
    
      # Create a new docx document.
      # @param filename [String] The filename of the docx file, without the docx extension.
      def initialize(filename, &block)
        @filename = filename + ".docx"
        @objects = [] # It contains all the DSL elements
        yield self if block
      end
      
      # Save the docx document to the target location.
      def save
        generate_archive(generate_content_types, generate_rels, generate_document)
      end

      # Add a new paragraph to the document.
      # @param options [Hash] Formatting options for the paragraph. See the full list in DocxGenerator::DSL::Paragraph.
      def paragraph(options = {}, &block)
        par = DocxGenerator::DSL::Paragraph.new(options)
        yield par if block
        @objects << par
      end

      # Add other objects to the document.
      # @param objects [Object] Objects (like paragraphs).
      # @return [DocxGenerator::DSL::Document] The document object.
      def add(*objects)
        objects.each do |object|
          @objects << object
        end
        self
      end
      
      private
      
        def generate_content_types
          <<EOF
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
  <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
  <Default Extension="xml" ContentType="application/xml"/>
  <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
</Types>
EOF
        end
        
        def generate_rels
          <<EOF
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
</Relationships>
EOF
        end
        
        def generate_document
          content = []
          @objects.each do |object|
            content << object.generate
          end

          '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' +
          Word::Document.new({ "xmlns:w" => "http://schemas.openxmlformats.org/wordprocessingml/2006/main" },
            [ Word::Body.new(content) ]).to_s
        end

        def generate_archive(content_types, rels, document)
          File.delete(@filename) if File.exists?(@filename)
          Zip::File.open(@filename, Zip::File::CREATE) do |docx|
            docx.mkdir('_rels')
            docx.mkdir('word')
            docx.get_output_stream('[Content_Types].xml') { |f| f.puts content_types }
            docx.get_output_stream('_rels/.rels') { |f| f.puts rels }
            docx.get_output_stream('word/document.xml') { |f| f.puts document }
          end
        end
    end
  end
end