require "rubytagpp"

require "tagsview"

=begin
  @short Main view
  @author Diego 'Flameeyes' Pettenò <flameeyes@gentoo.org>
  @version 0.1
=end
class JultaggerView < Qt::Widget
    slots 'dirSelected()',
          'fileSelected()',
          'dirActivated(const KFileItem*)',
          'cacheFiles()',
          'saveTags()',
          'fieldChange()'
    signals 'modified()',
            'saved()'

    def initialize(parent)
        super(parent)

        # Define all the layout
        # We use manual filling here because there's no way to achieve the
        # same with the usual Qt Designer .ui files
        wl = Qt::HBoxLayout.new(self, 11, 6)

        @splitter = Qt::Splitter.new(self, "splitter")
        @splitter.setOpaqueResize(true)

        sl = Qt::GridLayout.new(@splitter)

        @allDirs = KDE::FileTreeView.new(@splitter, "allDirs")
        @allDirs.addColumn( tr("Directory") )
        @allDirs.setResizePolicy(Qt::ListView::AutoOneFit)
        @allDirs.setRootIsDecorated(true)
        sl.add(@allDirs)
        connect(@allDirs, SIGNAL('selectionChanged(QListViewItem*)'), self, SLOT('dirSelected()'))

        @fileFrame = Qt::Frame.new(@splitter, "fileFrame")
        @fileFrame.setGeometry( Qt::Rect.new(260, 10, 352, 370) )
        @fileFrame.setFrameShape( Qt::Frame::NoFrame )
        @fileFrame.setFrameShadow( Qt::Frame::Plain )
        @fileFrame.setLineWidth(0)
        @fileFrame.setMaximumSize( 32767, 32767 )

        fileFrameLayout = Qt::VBoxLayout.new(@fileFrame, 0, 6, "fileFrameLayout")

        # @todo move it to the home instead of root
        @currDir = KDE::DirOperator.new( KDE::URL.new("file:///"), @fileFrame, "currDir" )
        @currDir.setMinimumSize( 350, 150 )
        @currDir.setMaximumSize( 32767, 32767 )

        @currDir.setMimeFilter(["audio/x-mp3", "audio/x-vorbis",
            "audio/x-flac", "audio/x-oggflac", # "audio/x-speex",
            "audio/vorbis"])
        @currDir.setView( KDE::File::Simple );
        @currDir.setMode( KDE::File::Files );
        @currDir.readConfig( KDE::Global.config, "currentDir" )
        fileFrameLayout.add(@currDir)
        connect(@currDir, SIGNAL('fileHighlighted(const KFileItem*)'), self, SLOT('fileSelected()'))
        connect(@currDir, SIGNAL('updateInformation(int, int)'), self, SLOT('cacheFiles()'))

        @tagsview = TagsViewUi.new(@fileFrame, "tagsview")
        fileFrameLayout.add(@tagsview)
        @tagsview.setMaximumSize( 32767, 32767 )

        @splitter.setCollapsible(@allDirs, false)
        @splitter.setCollapsible(@fileFrame, false)
        wl.add(@splitter)

        # Now we complete setting up the @allDirs tree
        home = @allDirs.addBranch(KDE::URL.new(Qt::Dir::home.path), tr("Home"),
          KDE::Global.iconLoader.loadIcon("folder_home", KDE::Icon::Small))
        @allDirs.setDirOnlyMode(home, true)

        @root = @allDirs.addBranch(KDE::URL.new("file:/"), tr("Root"),
          KDE::Global.iconLoader.loadIcon("folder_red", KDE::Icon::Small))
        @allDirs.setDirOnlyMode(@root, true)
    end

    def setupFocusSignals(enable = true)
        [ @tagsview.lineTitle, @tagsview.lineArtist, @tagsview.lineAlbum,
          @tagsview.lineComment, @tagsview.lineYear, @tagsview.lineTrack,
          @tagsview.lineComposer, @tagsview.lineOrigArtist,
          @tagsview.lineCopyright, @tagsview.lineURL, @tagsview.lineEncoder ].
        each { |w|
            if enable
                connect(w, SIGNAL('lostFocus()'), self, SLOT('fieldChange()') )
            else
                disconnect(w, SIGNAL('lostFocus()'))
            end
        }
    end

    def fieldChange
        return unless @selectedItems
        tag = sender.name.sub(/[a-z]+([A-Z])/, '\1').downcase
        if @selectedItems.size == 1
            emit modified() if @dirbuffer[@selectedItems[0].localPath][tag] != sender.text
            puts "#{@dirbuffer[@selectedItems[0].localPath][tag]} != #{sender.text}"
        else
            emit modified() if @tagsview.method(sender.name.sub('line', 'check')).call.checked? and @commontags[tag] != sender.text
        end
    end

    def tagsViewClear(multiple = false)
        [ @tagsview.lineTitle, @tagsview.lineArtist, @tagsview.lineAlbum,
          @tagsview.lineComment, @tagsview.lineYear, @tagsview.lineTrack,
          @tagsview.comboGenre ].each { |w|

            w.clear
            w.enabled = true
        }

        [ @tagsview.checkTitle, @tagsview.checkArtist, @tagsview.checkAlbum,
          @tagsview.checkComment, @tagsview.checkYear, @tagsview.checkTrack,
          @tagsview.checkGenre ].each { |w|

            w.enabled = multiple
            w.checked = false
        }
    end

    def dirSelected()
        tagsViewClear
        @currDir.setURL(@allDirs.currentURL, false)

    end

    @@alltags = [ "title", "artist", "album", "comment", "year", "track" ]

    def saveTags
        return unless @selectedItems
        updateCache

        @selectedItems.each { |f|
            fref = TagLib::FileRef.new(f.localPath)

            @@alltags.each { |tag|
                saveTag(fref.tag, tag, @dirbuffer[f.localPath][tag])
            }

            unless fref.save
                puts "Something gone wrong with #{f.localPath}"
            end
        }

        emit saved()
    end

    def cacheFiles()
        @dirbuffer = Hash.new
        @currDir.dirLister.items.each { |f|
            filecache = Hash.new
            fref = TagLib::FileRef.new(f.localPath)
            puts "Error with file #{f.localPath}\n." if fref.null?

            @@alltags.each { |tag|
                filecache[tag] = loadTag(fref.tag, tag)
            }

            @dirbuffer[f.localPath] = filecache
            puts "Cached #{f.localPath}\n"
        }
    end

    def updateCache()
        return unless @selectedItems

        modified = false
        @selectedItems.each { |item|
            cache = @dirbuffer[item.localPath]
            next unless cache
            @@alltags.each { |tag|
                prevtag = cache[tag].to_s
                cache[tag] = @tagsview.method("line#{tag.capitalize}").call.text.dup \
                  if @selectedItems.size == 1 or @tagsview.method("check#{tag.capitalize}").call.checked?
                modified ||= cache[tag] != prevtag
            }
            @dirbuffer[item.localPath] = cache.dup
        }

        emit modified() if modified
    end

    def fileSelected()
        setupFocusSignals(false)
        updateCache if @selectedItems
        tagsViewClear(@currDir.selectedItems && @currDir.selectedItems.size > 1)
        @selectedItems = nil
        return unless @currDir.selectedItems and @currDir.selectedItems.size > 0

        @selectedItems = @currDir.selectedItems
        if @selectedItems.size == 1
            puts "Loading #{@currDir.selectedItems[0].localPath} from cache\n"
            file = @dirbuffer[@currDir.selectedItems[0].localPath]

            @@alltags.each { |tag|
                @tagsview.method("line#{tag.capitalize}").call.text = file[tag].to_s.dup
            }
            #@tagsview.comboGenre.setText(file.tag.genre)
        else
            @tagsview.lineTitle.setEnabled(false)
            @tagsview.lineTrack.setEnabled(false)

            @commontags = Hash.new
            @selectedItems.each { |f|
                file = @dirbuffer[f.localPath]
                [ "artist", "album", "comment", "year" ].each { |tag|
                    @commontags[tag] = file[tag] unless @commontags.has_key?(tag)
                    @commontags[tag] = "" unless @commontags[tag] == file[tag]
                }
            }

            [ "artist", "album", "comment", "year", "track" ].each { |tag|
                @tagsview.method("line#{tag.capitalize}").call.text = @commontags[tag].to_s.dup
            }
            #@tagsview.comboGenre.setText(commontags["genre"].to_s)
        end
        setupFocusSignals(true)
    end

    def loadTag(tag, tagname)
        # If it's one of the base tags, just get them directly
        return tag.method(tagname).call if [ "title", "artist", "album", "comment", "track", "year" ].include?(tagname)
    end

    def saveTag(tag, tagname, tagval)
        return tag.method("#{tagname}=").call(tagval) if [ "title", "artist", "album", "comment" ].include?(tagname)

        # These are integers, needs to be passed differently
        return tag.method("#{tagname}=").call(tagval.to_i) if [ "track", "year" ].include?(tagname)
    end
end

## Kate modeline: leave at the end
# kate: indent-width 4; replace-trailing-space-save 1; space-indent 1; backspace-indents 1; indent-mode normal;
