001package org.xbib.standardnumber; 002 003import java.util.regex.Matcher; 004import java.util.regex.Pattern; 005 006/** 007 * ISO 15707 International Standard Musical Work Code (ISWC) 008 * 009 * International Standard Musical Work Code (ISWC) is a unique identifier for 010 * musical works, similar to ISBN. 011 * 012 * Its primary purpose is in collecting society administration, and to clearly identify works in 013 * legal contracts. It would also be useful in library cataloging. 014 * 015 * Due to the fact that a musical work can have multiple authors, it is inevitable that, 016 * on rare occasions, a duplicate ISWC might exist and might not be detected immediately. 017 * 018 * Because of the existing business practices among collecting societies, it is not possible 019 * to simply declare an ISWC as obsolete. In such cases, as soon as they are identified, 020 * the system will deal with duplicate registrations by linking such registration records 021 * in the ISWC database. 022 * 023 */ 024public class ISWC extends AbstractStandardNumber implements Comparable<ISWC>, StandardNumber { 025 026 private static final Pattern PATTERN = Pattern.compile("[\\p{Alnum}\\-\\s]{10,13}"); 027 028 private String value; 029 030 private String formatted; 031 032 @Override 033 public String type() { 034 return "iswc"; 035 } 036 037 @Override 038 public int compareTo(ISWC iswc) { 039 return iswc != null ? normalizedValue().compareTo(iswc.normalizedValue()) : -1; 040 } 041 042 @Override 043 public ISWC set(CharSequence value) { 044 this.value = value != null ? value.toString() : null; 045 return this; 046 } 047 048 @Override 049 public ISWC createChecksum(boolean createChecksum) { 050 return this; 051 } 052 053 @Override 054 public ISWC normalize() { 055 Matcher m = PATTERN.matcher(value); 056 if (m.find()) { 057 this.value = clean(value.substring(m.start(), m.end())); 058 } 059 return this; 060 } 061 062 @Override 063 public boolean isValid() { 064 return value != null && !value.isEmpty() && check(); 065 } 066 067 @Override 068 public ISWC verify() throws NumberFormatException { 069 if (value == null || value.isEmpty()) { 070 throw new NumberFormatException("invalid"); 071 } 072 if (!check()) { 073 throw new NumberFormatException("bad createChecksum"); 074 } 075 return this; 076 } 077 078 @Override 079 public String normalizedValue() { 080 return value; 081 } 082 083 @Override 084 public String format() { 085 return formatted; 086 } 087 088 @Override 089 public ISWC reset() { 090 this.value = null; 091 this.formatted = null; 092 return this; 093 } 094 095 private boolean check() { 096 int l = value.length(); 097 int checksum = 1; 098 int val; 099 int weight; 100 for (int i = 1; i < l; i++) { 101 val = value.charAt(i) - '0'; 102 weight = i < l - 1 ? i : 1; 103 checksum += val * weight; 104 } 105 int chk = checksum % 10; 106 return chk == 0; 107 } 108 109 private String clean(String raw) { 110 if (raw == null) { 111 return null; 112 } 113 StringBuilder sb = new StringBuilder(raw); 114 int i = sb.indexOf("-"); 115 while (i >= 0) { 116 sb.deleteCharAt(i); 117 i = sb.indexOf("-"); 118 } 119 i = sb.indexOf(" "); 120 while (i >= 0) { 121 sb.deleteCharAt(i); 122 i = sb.indexOf(" "); 123 } 124 if (sb.indexOf("ISWC") == 0) { 125 sb = new StringBuilder(sb.substring(4)); 126 } 127 if (sb.length() > 10) { 128 this.formatted = "ISWC " 129 + "T-" 130 + sb.substring(1,10) + "-" 131 + sb.substring(10,11); 132 } 133 return sb.toString(); 134 } 135}