#!/usr/bin/python
from optparse import OptionParser
import sys, os, re, zipfile
import urllib2
import subprocess


class WPM(object):
    wp_latest = "http://wordpress.org/latest.zip"
    plugins_svn = "http://plugins.svn.wordpress.org"
    plugin_db_path = os.path.expanduser('~/.wpm/available_plugins')
    target_location = None

    def __init__(self):
        self.parser = OptionParser()
        self.parser.usage = "wpm installframwork|install|search|update <plugin name> <location> [options]"
    
    def main(self):
        self.set_options()
        self.options, self.args = self.parser.parse_args()
        
        self._set_location()

        try:
            getattr(self,self.args[0])()
        except IndexError:
            print "Please specify a command."
            return
        except AttributeError:
            print "Invalid Command. Usage: %s" % self.parser.usage
            return

        print "Installation Complete."
    
    def set_options(self):
        self.parser.add_option("-r", "--requirements", metavar="FILE", help="The location of the requirements file",)

    """
    Downloads and installs the WordPress framework.
    """        
    def installframework(self):
        file = ''.join([self.target_location,'/','wordpres.zip'])
        data = self._download_data(self.wp_latest)
        local = open(file, 'w')
        local.write(data)
        local.close()
        self._extract(file)

    """
    Downloads and unzips a plugin
    """        
    def install(self):
 
        if self.options.__dict__.get('requirements',None) is not None:
            file = open(self.options.__dict__.get('requirements'), 'r')
            requirements = file.readlines()
            file.close()
            
            for line in requirements:
                self._route_install(line)
        else:
            self._route_install(self.args[1])


    """
    Search for available plugins to install
    """      
    def search(self):

        local = self._get_plugin_database()
        search_str = sys.argv[2]
        
        for line in local.readlines():
            if re.search(search_str, line): print line.replace("\r\n",'')


    """
    List all installed plugins
    """            
    def list(self):
        try:
            pass
        except:
            NotImplementedError

    """
    Update the local list of plugins
    """
    def update(self):
        
        print "Getting plugins list"

        data =self._download_data(self.plugins_svn)
        local = self._get_plugin_database()
        existing_contents = list(local.read())
        
        plugins = re.findall('">(.*)/</a>',data)

        local.seek(0)
        local.write("\r\n".join(plugins))
        
        local.close()


    """
    Sets and verifies the install path
    """
    def _set_location(self):
        print "Verifying install location"
        for arg in self.args:
            path = os.path.abspath(self.args[-1])
            if os.path.exists(path):
                self.target_location = path

        if (self.target_location is None):
            print "Invalid install location specified, or none provided. Falling back to current directory."
            self.target_location = os.getcwd()

    """
    Get the list of available plugins
    """        
    def _get_plugin_database(self):
        return open(os.path.expanduser('~/.wpm/available_plugins'), 'r+')


    """
    Common method to download a file from a given url
    """        
    def _download_data(self, url):
        
        conn = urllib2.urlopen(url)
        
        data = ""
        
        file_size_dl = 0
        block_sz = 500
        while True:
            buffer = conn.read(block_sz)
            if not buffer:
                break

            file_size_dl += len(buffer)
            data += buffer
            status = "Downloaded %s bytes" % (file_size_dl)
            status = status + chr(8)*(len(status)+2)
            print status,
        
        return data

    """
    Unzip a plugin in .zip format
    """        
    def _extract(self, file):
        print "\r\nExtracting ..."
        z = zipfile.ZipFile(file)
        z.extractall(self.target_location)
        print "Deleting zip file"
        os.remove(file)


    """
    Decides which protocol to use to install the plugin
    """
    def _route_install(self, line):
        
        if line == '' or line[:1] == '#':
            return
        elif line[:4] == 'svn+' or line[:4] == "git+":
            result = self._install_remote(line)
        else:    
            result = self._wp_svn_install(line)
        
        if result:
            print "Installed " + line
        

    """
    Download and extract the specified plugin from the
    official WordPress plugin repository
    """    
    def _wp_svn_install(self, plugin_name):
        svn_url = '/'.join([self.plugins_svn,plugin_name.replace("\n",''),'trunk'])
        if not self._overwrite_if_exists(plugin_name): return
        print "Exporting %s from Wordpress SVN" % (plugin_name)
        self._run_command(['svn','export',svn_url,'--force',''.join([self.target_location,'/',plugin_name])])
        return True

    """
    Installs from a remote SVN or GIT repository with a properly
    formatted location string
    """
    def _install_remote(self, location_string=None):
        parts = location_string[4:].split('#')
        if location_string[:3] == 'git':
            self._generic_git_install(parts[0], parts[1])
        elif location_string[:3] == 'svn':
            self._generic_svn_install(parts[0], parts[1])
        else:
            print "Invalid protocol %s."
            return False
    
    """
    Exports from the trunk of an svn repository
    """        
    def _generic_svn_install(self, url=None, name=None):
        cmd = ['svn','export','--force',url,''.join([self.target_location,'/',name])]
        if not self._overwrite_if_exists(name): return
        print "Exporting %s from %s" % (name, url)        
        self._run_command(cmd)
        
    """
    Clones a git repository
    TODO: Add the option to upgrade
    """        
    def _generic_git_install(self, url=None, name=None):
        cmd = ['git','clone',url,''.join([self.target_location+'/'+name]).strip()]
        print ' '.join(cmd)
        print "Cloning %s from %s" % (name, url)
        self._run_command(cmd)
    
    """
    Runs a command
    """        
    def _run_command(self, cmd_list):
        proc = subprocess.Popen(cmd_list,stdout=subprocess.PIPE)
        for line in proc.stdout:
            if line is not "\r\n": print line        

    def _overwrite_if_exists(self, plugin_name):
        target_dir = ''.join([self.target_location,'/',plugin_name.strip()])
        if os.path.exists(target_dir):
            input = raw_input('Plugin %s already exists. Should I overwrite?: (y or n)' % (plugin_name))
            if input == 'n':
                print "Cancelled."
                return False
        return True
    

    """
    Create the setup directory that contains the package repositories
    """        
    def setup(self):

        print "Creating .wpm directory"

        try:
            os.mkdir(os.path.expanduser('~/.wpm'))
        except OSError:
            print ".wpm directory already exists."
        else:
            print "Couldn't create .wpm directory. Exiting."

        if not os.path.exists(self.plugin_db_path):
            file = open(self.plugin_db_path, 'w')
            file.write('')
            file.close()        
   
        self.update()
        
        print "Finished setup"
        

if __name__ == '__main__':
    wpm = WPM()
    wpm.main()
